A simple two-step model for an application request is:
Accept the request.
Process the request.
PUT /user/123 { "email": "cameron@example.com" } update user set email="cameron@example.com" where id = 123
Only the effect of processing the request is recorded in the database, e.g. a user is updated. The ephemeral request is not recorded. It is useful to introduce an intermediary step to record the entire request then process that recorded request.
Accept the request.
Record the request.
Process the recorded request.
Requests are recorded in a request
table.
create table request id: int metadata: text body: text process_at: timestamp processed_at: timestamp, default: null
Instead of processing the request directly, the request is recorded and that record is processed.
PUT /user/123 { "email": "cameron@example.com" } insert into request (metadata, body, process_at) values ( '{"type": "POST", "path": "/user/123"}', '{"email": "cameron@example.com"}', now() ) update user set email="cameron@example.com" where id = 123 update request set processed_at = now() where id = 1
This three-step model of recording requests and then processing the record creates these advantages.
Recorded requests can be replayed because we have the record in our database.
Requests that don't require an immediate response can be processed asynchronously to reduce the immediate processing load.
All input channels (e.g. API call, console command) conform to the same recorded request format.
Requests can be scheduled to occur in the future by setting a future process_at
timestamp.