This pattern describes how to manage long-running or background processing tasks in a REST-based API, allowing clients to initiate a process and check its progress asynchronously.
Details
When a client requests a long-running task, the API immediately returns a response with an HTTP status code of 202 Accepted. This response includes a Location header that points to a resource where the client can check the status of the task. The client then periodically polls this URL to get updates on the task’s progress until it is complete.
Common Pattern Names/Synonyms
- Asynchronous Task Pattern
- Deferred Result Pattern
- 202 Accepted Pattern
- Polling Pattern
- Long Running Operation Polling
Common Use Cases
- Data Processing: Initiating a data import process that takes time to complete.
- Report Generation: Requesting the generation of a report that requires complex calculations or aggregation of large datasets.
- Video Processing: Starting a video encoding or transformation task that runs in the background.
When to Use
- High scalability needs: Ideal for systems requiring concurrent handling of numerous requests.
- Variable task durations: Effective for operations with unpredictable processing times.
- Client-specific polling flexibility: Suitable when clients may vary in their needs for update frequency, or for applications needing frequent updates on a resource’s state, but the client is unable to leverage Webhooks and/or is not capable of using Websockets or other server-push notification options.
When Not to Use
- Immediate feedback required: Not suitable for operations where instant updates are crucial.
- Risk of over-polling: Avoid if there is a concern that clients may poll too frequently, potentially leading to performance issues.
Examples
Creating a New Resource
Request:
POST /api/reports HTTP/1.1
Host: example.com
Content-Type: application/json
{
"reportType": "yearly-sales",
"parameters": {
"year": "2023"
}
}
Response:
HTTP/1.1 202 Accepted
Location: /api/reports/12345/status
Polling for Status
Request:
GET /api/reports/12345/status HTTP/1.1
Host: example.com
Response (In Progress and Complete):
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "In Progress",
"estimatedTimeRemaining": "120 seconds"
}
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "Complete",
"reportURL": "/api/reports/12345/download"
}
Sequence Diagram (queries background job status)
sequenceDiagram
participant Client
participant Server
participant BackgroundProcess as Background Process
Client->>Server: 1. POST /api/reports
Server->>BackgroundProcess: 2. Initiate Background Process
Server-->>Client: 3. 202 Accepted (Location: /api/reports/123)
Client->>Server: 4. GET /api/reports/123/status
Server->>BackgroundProcess: 5. Query Process Status
Server-->>Client: 6. 200 OK (Status: In Progress)
Client->>Server: 7. GET /api/reports/123/status
Server->>BackgroundProcess: 8. Query Process Status
Server-->>Client: 9. 200 OK (Status: Complete, Report URL: /api/download)
Sequence Diagram (API is updated via message to update state)
sequenceDiagram
participant Client
participant Server
participant MessageBroker as Message Broker
participant BackgroundProcess as Background Process
participant Database
Client->>Server: 1. POST /api/reports
Server->>BackgroundProcess: 2. Initiate Background Process
Server-->>Client: 3. 202 Accepted (Location: /api/reports/123)
BackgroundProcess->>MessageBroker: 4. Post Job Completion Status
MessageBroker->>Server: 5. Notify API of Job Completion
Server->>Database: 6. Update Resource Status in DB
Client->>Server: 7. GET /api/reports/123/status
Server->>Database: 8. Retrieve Status from DB
Server-->>Client: 9. 200 OK (Status: Complete, Report URL: /api/download)
OpenAPI Example
openapi: 3.0.0
info:
title: Asynchronous Processing API
version: 1.0.0
servers:
- url: 'https://api.example.com'
paths:
/reports:
post:
summary: Initiates a report generation
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
reportType:
type: string
parameters:
type: object
properties:
year:
type: string
examples:
reportRequest:
value:
reportType: "yearly-sales"
parameters:
year: "2023"
responses:
'202':
description: Report generation initiated
headers:
Location:
schema:
type: string
description: URI to poll for report status
/reports/{reportId}/status:
get:
summary: Polls the status of the report generation
parameters:
- name: reportId
in: path
required: true
schema:
type: string
responses:
'200':
description: Current status of the report
content:
application/json:
schema:
type: object
properties:
status:
type: string
estimatedTimeRemaining:
type: string
examples:
inProgress:
value:
status: "In Progress"
estimatedTimeRemaining: "120 seconds"
complete:
value:
status: "Complete"
reportURL: "/reports/12345/download"