Asynchronous execution allows an initiating request or caller to continue without waiting for the requested work to finish. In applications and services, this often means accepting a request, processing it separately, and providing another way to discover its status and result.

The important distinction is simple: accepting work is not the same as completing it. A useful asynchronous interface makes that distinction visible throughout the operation’s life, including delays, failures, cancellation, and periods when the client cannot reach the service.

What asynchronous execution means

A synchronous interaction usually keeps the caller waiting until the requested work returns a result or an error. An asynchronous interaction separates initiation from completion: control returns before the work has finished, and completion is observed through another mechanism.

Examples include generating a large export, processing uploaded media, rebuilding a search index, or running a document-analysis workflow. These operations may take longer than a reasonable request-response window, or they may need to wait for capacity or another service.

The same term also appears in programming-language features, event loops, and nonblocking input/output. Those mechanisms can support asynchronous execution, but they do not by themselves establish a durable background workflow. An asynchronous function might still belong to a request that must remain open until the response is ready.

This article focuses on work that continues beyond the initiating interaction.

Asynchronous does not necessarily mean parallel

Asynchronous work does not require several tasks to execute simultaneously. A single worker can process queued operations one at a time while clients continue doing other things. Parallel execution concerns simultaneous work; asynchronous interaction concerns whether the caller must wait for completion.

Asynchronous does not guarantee eventual success

Separating work from a request does not automatically make it persistent, recoverable, or reliable. A background task held only in process memory may disappear when that process restarts. A queued operation may fail, expire, or remain blocked unless the system provides explicit handling for those outcomes.

The operation-and-status pattern

One useful approach is to represent each accepted unit of work as an operation with its own identifier and status resource. The client receives a reference to that operation rather than waiting for the final result.

For example, an application might accept a request to generate an export:

POST /exports

HTTP/1.1 202 Accepted
Location: /operations/op_7f3a
Content-Type: application/json

{
  "operationId": "op_7f3a",
  "status": "queued",
  "statusUrl": "/operations/op_7f3a"
}

In HTTP, 202 Accepted indicates that a request has been accepted for processing, but processing has not finished. It does not promise successful completion. In this example, the API uses the Location header and response body to identify a status resource; that is an interface convention, not something the status code automatically supplies.

The client can later inspect that resource:

GET /operations/op_7f3a

HTTP/1.1 200 OK
Content-Type: application/json

{
  "operationId": "op_7f3a",
  "status": "running",
  "phase": "building-file",
  "updatedAt": "2026-11-02T14:32:10Z"
}

When the work finishes, the same resource can describe the outcome and provide a result reference.

This pattern gives clients a stable place to return after navigation, a lost connection, or an application restart. It is not the definition of asynchronous execution. Futures, event streams, message-based replies, callbacks, and other mechanisms can also communicate completion.

The underlying requirement is that the completion contract be understandable: how does the caller learn what happened, and what evidence supports that answer?

Representing execution state

An operation’s state should distinguish meaningful stages without exposing every internal implementation detail. The labels vary between systems, but their meanings should be documented and consistent.

Accepted
The service has agreed to handle the request under its documented acceptance contract. This does not establish that execution has started.
Queued or scheduled
The work is waiting for execution. Scheduled work may also have a future eligibility time.
Running
Execution has begun. This state alone does not prove that a worker is still healthy or making progress.
Succeeded
The operation has met its defined completion conditions, and any promised result is ready.
Failed
The operation has ended without meeting its completion conditions. Any partial effects should be explained separately.
Canceled
The operation has reached the system’s defined canceled outcome. That definition must explain whether any completed effects remain.

Not every system needs a separate public state for acceptance and queuing. A service may commit the operation record and queue entry together, then return queued. The conceptual distinction still matters when deciding what the response promises.

Cancellation requests are not terminal outcomes

A state such as cancellation_requested normally means the service has received an instruction to stop. The operation may still be running while a worker reaches a safe stopping point. It may even finish before cancellation takes effect.

Similarly, an internal retry delay is not necessarily a final failure. A public state such as waiting_to_retry may help when the delay matters to the user.

Separate the operation from its execution attempts

One logical operation may require several worker attempts. If a worker crashes and another resumes the work, the operation identifier should generally remain stable while attempt records change underneath it.

This distinction lets the system preserve a coherent history without presenting every recovery attempt as a new user request.

Define what “finished” includes

An export is not necessarily complete when file generation ends. If success promises a downloadable file, the file must also be stored and available through the promised retrieval path.

Completion should reflect the caller’s task, not merely the last convenient internal step. This is the same distinction explored in network success versus task success.

Durability and client disconnection

If an interface promises that accepted work survives the original connection, the server must establish that responsibility before acknowledging acceptance. Depending on the design, this may involve persisting an operation record, publishing a durable message, or committing a recoverable workflow state.

Writing an operation record and sending a queue message are separate actions in many systems. A crash between them can leave accepted work with no worker scheduled to perform it. Designs such as a transactional outbox can address this coordination gap.

A durable operation record is still not a guarantee of success. Recovery also depends on how workers claim tasks, detect interrupted attempts, preserve progress, and handle repeated delivery.

A disconnected client does not necessarily stop the work

After acceptance, the client’s connection and the operation’s execution can have independent lifetimes. Closing a browser tab may leave the operation running. In another system, disconnecting may trigger cancellation or cause request-scoped work to be abandoned.

Neither behavior follows automatically from the word “asynchronous.” The interface should state which behavior applies.

For work intended to survive disconnection, the application should preserve a route back to it: an operation history, a saved reference, or another authorized lookup mechanism. A status URL is less useful if the user loses it when the page closes.

Polling, notifications, and progress

Clients need a way to observe work without keeping the original request open. Several mechanisms can serve that purpose.

Polling a status resource

Polling means checking status periodically. It is straightforward and can recover naturally after temporary network failures.

The polling interval should suit the operation’s expected duration and the service’s capacity. Clients may use backoff and jitter to avoid excessive synchronized requests, honor documented server timing guidance, and stop polling when the operation reaches a terminal state.

A failed poll is a failed attempt to retrieve status. It is not evidence that the underlying operation failed.

Callbacks, webhooks, and event notifications

A service can also send a notification when the operation changes state. This may reduce unnecessary checks, but notification delivery has its own failure modes. Messages may arrive late, more than once, or out of order, depending on the delivery contract.

Consumers should authenticate notifications and handle duplicates appropriately. Where a status resource exists, a notification can prompt the client to retrieve the current authoritative state rather than treating every received message as the latest truth.

Notifications and polling can complement each other: notifications provide timely signals, while status retrieval supports reconciliation after missed delivery.

Report progress without inventing precision

Progress is useful when it has a defensible meaning. “320 of 800 records processed” is meaningful when the total is known and the units are comparable. A percentage can mislead when later stages have unpredictable costs.

For variable work, a named phase may be more honest:

  • Waiting for a worker
  • Reading source records
  • Building the export
  • Making the file available

Distinguish the last status change, the last worker heartbeat, and the last measurable progress. A worker can be alive without advancing the task. A status response can also be stale, particularly when it comes from a cache or replica.

For user interfaces, progress should remain available as readable text rather than relying only on animation or color. The guidance in loading states applies to this longer-lived work as well.

Failures, retries, and cancellation

Asynchronous interfaces must distinguish uncertainty about communication from evidence about execution.

The submission response can be lost

Suppose a client submits an export request, the service accepts it, and the response never reaches the client. The client does not yet know whether an operation exists. Submitting the same request again may create a duplicate.

A documented idempotency-key mechanism can let the client retry the submission while recovering the same logical operation. Its guarantees depend on scope, retention, concurrent-request handling, and how the service treats a reused key with different request content.

An operation identifier and an idempotency key serve different purposes: one identifies accepted work; the other can help reconcile repeated attempts to initiate that work.

Status retrieval can succeed while the operation has failed

A successful HTTP response from a status endpoint means the status representation was retrieved successfully. That representation may report failed.

Conversely, an HTTP error from the status endpoint may mean the service cannot currently report the outcome. It should not automatically be interpreted as an operation failure. A timeout establishes that a waiting limit was reached, not that the underlying work stopped.

Retries must account for effects that already happened

A worker may fail after changing data but before recording completion. Repeating the entire task can then repeat an external effect.

Recovery may require idempotent steps, checkpoints, deduplication, or reconciliation with the affected system. The right approach depends on the action. Retry safety is a separate design concern from whether execution is asynchronous.

A failed operation may also have partially completed. Reporting failure should not imply that nothing changed.

Cancellation is not rollback

Cancellation may prevent queued work from starting, stop further steps, or request cooperative termination. It does not inherently undo completed actions.

A useful cancellation contract explains what can still change, which effects remain, and how a race between completion and cancellation is resolved. See cancellation semantics for that distinction in more detail.

Results, permissions, and retention

A successful operation should make its result discoverable without requiring the client to reconstruct internal storage paths. The status representation might contain a small result directly or link to a separate resource:

{
  "operationId": "op_7f3a",
  "status": "succeeded",
  "resultUrl": "/exports/export_91",
  "completedAt": "2026-11-02T14:34:22Z"
}

Operation records and results may have different retention periods. An export file might expire while its operation history remains available. That does not change the historical fact that the operation succeeded; it changes whether the result can still be retrieved.

Document those lifetimes. A missing status resource should not silently stand in for success, failure, cancellation, or expiration.

Authorization also applies throughout the operation’s life. An identifier is not permission. Status records may reveal filenames, customer details, or processing errors, so both status and result endpoints need appropriate access checks.

Long-running work may also outlive the permissions or approval that originally authorized it. Systems handling consequential actions should define whether authority is checked only at submission or again before execution. An earlier decision may become stale before the action occurs, as discussed in human approval and stale decisions.

A practical design checklist

Before exposing an asynchronous operation, make sure the interface can answer these questions:

  • Acceptance: What responsibility has the service taken on when it acknowledges the request?
  • Identity: How can the client find the same operation again?
  • State: Can the client distinguish waiting, running, and terminal outcomes?
  • Recovery: What happens after a worker crash, a lost response, or repeated delivery?
  • Observation: How does the client discover current status, and how fresh is that information?
  • Completion: What must be true before success is reported?
  • Cancellation: What does a stop request mean, and what effects may remain?
  • Results: Where is the result, who may access it, and when does it expire?

Asynchronous execution separates the lifetime of an interaction from the lifetime of the work it initiates. A well-designed interface preserves continuity across that separation: it gives the work an identity, makes its state inspectable, and distinguishes confirmed outcomes from periods of uncertainty.