# Waiting for follow-on work

An action does its own database work and leaves the rest, such as a second
call to a provider, to subscribers: code that runs when an event the action
emits is delivered ([Subscribers](subscribers.md)).
Without anything more, the route answers once the action commits, and that
work carries on afterwards. When the client wants the finished result
rather than a `202`, the route waits for the work with `settle:`:

```jadpo
POST /orders {
    input: PlaceOrder
    output: OrderView
    status: SuccessStatus.created
    run: place_order(input, current_principal.user)
    settle: {
        answer: order_view(result.id)
        within: 5s
    }
}
```

This route places the order, then waits up to 5 seconds for the work it
set off. It answers with `order_view(result.id)`: 201 if the work finished,
202 if the 5 seconds ran out first. The body is an `OrderView` either way.

## What the route waits for

After the action commits, the runtime delivers the events it emitted at
once, while the request waits, and then the events their subscribers emit
in turn. They run in the request's own invocation, each delivery as any is
delivered
([Delivery: at least once, safe to repeat](delivery-at-least-once-safe-to-repeat.md)),
as the system limited to its event's tenant
([Background work](background-work.md)). The request's caller is
given back before the answer runs.

The work has settled when every one of those deliveries has succeeded,
failed for good, or been parked as `outcome_unknown`. That covers a failure
that isn't retried, a defect (a bug in the code, such as an `Int`
overflow), a subscriber the build no longer has, and an event 16 deep in a
chain of events (`event_chain_limit`), so a loop of events settles too.

Some work can't be waited for:

- A delivery left to retry after a pause (`unavailable`, `rate_limited`,
  or a store that couldn't be reached) hasn't settled, so the route stops
  waiting at once and answers 202.
- So does a delivery the request couldn't claim.
- So does a batch run the action started. A batch is long work no route
  waits on, so a route whose action starts one answers 202
  ([Batches: work over many items](batches-work-over-many-items.md)).

Waiting stops at the first such piece. The rest is left for after the
response, and a retry is left to the outbox's sweep, the runtime's regular
pass over deliveries that are due
([Retries and giving up](retries-and-giving-up.md)).

## The answer

Then the route runs `answer:`. It is a named query, given `result` (what
the action returned) or fields read through it, and nothing else; the
query reads who is asking through its policy. It runs as the request's
caller and under the query's policy, as a `GET` running it would. The route
answers with its result and the route's `status:`.

If `within:` passes first, the route runs the same query and answers
`202`. So the client gets the same `output:` either way, and knows from the
status whether the work finished. The work carries on in the background
either way, exactly as it would without `settle:`.

The query's failures are the route's too, beside the action's, in OpenAPI
and the record. A query that fails, through its `missing:` say, answers
with that failure, though the action committed.

## Rules

- With `settle:`, `output:` is the query's result type, not the action's.
- `within:` counts from when the request came in, as `deadline:` does. It
  must be shorter than the deadline, leaving the answer time to run, or it
  is `route.settle_invalid`. The answer isn't held to the deadline, because
  the action has already committed, so waiting never ends in a 504.
- When `within:` passes, the subscriber's action that is running is
  dropped and nothing it did is kept. Its delivery goes back to `pending`,
  due at once, and that attempt isn't counted. Only its body is cut short,
  never its commit, and the delivery's own statements are never cut short,
  so a claim is never left in doubt.
- `settle:` goes only on a route that runs an action and answers
  `SuccessStatus.ok` or `.created`, or it is `route.settle_invalid`. A
  `GET` sets off nothing to wait for, `.accepted` would make both answers
  202, and `.no_content` sends no answer.
- Only work this action set off is waited for, never other requests' work
  or published copies of events
  ([Where events travel](where-events-travel.md)).

## Repeats, OpenAPI and tests

- A repeat with the same `Idempotency-Key`
  ([Idempotent writes](idempotent-writes.md)) runs the answer query again,
  rather than replaying a stored body, so it shows how far the work has
  got. The key keeps the query's arguments, each written by its
  parameter's codec. A repeat answers 202 until the work is known to have
  settled, and the route's status after that. So a process that stops
  between the commit and the answer never has a repeat say the work
  finished.
- OpenAPI lists the route's status, "once the work it set off has
  settled", and 202, each sending the query's result, and says a repeat
  runs the answer again. The API record adds a `settle within <duration>`
  line to the route.
- A route test's request waits in the same way. A test host's timers never
  go off, so `within:` never passes in a test, and a follow-on left to
  retry gives 202.
