-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Async Polling Standards #70
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
# Asynchronous | ||
|
||
## Overview | ||
|
||
There are number of situations where REST API endpoints require longer processing time to handle specific requests. Those type of particular operations have to run in the background outside of the request processing scope. These API endpoints should be designed to handle asynchronous communication in order to make the results of the request available to the consumer. | ||
|
||
There are couple ways to accomplish asynchronous communication in REST APIs and those are not mutually exclusive, including polling, websockets and webhooks. | ||
|
||
```note | ||
At this time only asynchronous communication through polling are provided in the API Standards. | ||
``` | ||
|
||
## Polling (Resource without Status Monitor) | ||
|
||
Overall guidelines for asynchronous requests are: | ||
- API requests **SHOULD** be implemented as asynchronous if the 99th percentile response time is greater than 5s. | ||
- API requests **SHOULD NOT** decide or interpret whether a response will be asynchronous or synchronous dynamically at runtime. An endpoint should be either synchronous or asynchronous, but not both. | ||
- PATCH requests **MUST NOT** be used as asynchronous request initiation. If entity update is required and takes more than established time then it **MUST** be implemented as a POST request. | ||
|
||
All asynchronous endpoint requests start with initiation. Since long-running requests need to be processed on background, asynchronous requests should initiate those processes with necessary input parameters. Background process details should be returned. | ||
|
||
- Asynchronous requests **MUST** be a `POST` method, and should be represented as a resource, not an action-style endpoint. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will we allow async on DELETE? if so, it doesn't work with the pattern where status monitor and resource are the same object. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why DELETE conflict with status monitor? I think background job can be cancelled, but not deleted. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the current pattern the status monitor and the resource are the same. So you'd have to make a GET request to the resource with a given id... and poll until you get a 404 on it? |
||
- Asynchronous requests **SHOULD** be have an associated `GET` method for the same resource to retrieve the status of the request. | ||
- Asynchronous requests **MUST** perform as much validation as possible before initiating the long-running process, and return 400 (Bad Request) [error response](errors.md) if validation fails. | ||
- Asynchronous requests **MUST** return error details as part of completed long-running process response (other than request validation failures). | ||
- Asynchronous requests **MUST** return 202 (Accepted) response status code when a long-running processing requests was successfully initiated. | ||
- No other 2xx codes **SHOULD** be returned in response to the asynchronous request initialization, even if request has completed before the initiating request returns. | ||
- `Operation-Id` header is **MAY** be supported and can be provided as part of the request. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What type is |
||
- Process ID **SHOULD** be automatically generated and returned to the client if `Operation-Id` header is not provided. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably worth calling out that newly generated process id will be returned in the same Operation-Id header it it wasn't specified by client in request There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I struggled on the reason why we would want the Client/Consumer to ever specify the operation-id... and why not we always create and return one from the API? |
||
- Asynchronous request **MUST** have a response body that extends from the following schema: | ||
```json | ||
{ | ||
"id": "string", // required: unique id representing the resource | ||
"ref": "sps-ref", // optional | ||
"status": "SUCCEEDED" | "FAILED" | "RUNNING" | "NOT_STARTED" | "CANCELED", // required | ||
"detail": "same as detail from bulk... maybe error message? or complex object?",// required | ||
"result": "", // optional | ||
"completenessDescription": "percentage?", // optional | ||
"createdDateTime": "", // required | ||
"createdBy": "" | null, // optional | ||
"completedDateTime": "" | null, // required | ||
...EXTENDED... | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this would be the response body of the status monitor or the object to be extended where status monitor and resource are combined. |
||
``` | ||
|
||
Example workflow for an asynchronous resource creation request: | ||
|
||
``` | ||
// REQUEST | ||
POST /reports // initiates long running processing by posting job with new parameters | ||
Operation-Id: f7cf8412-08ed-40c9-ac1b-296da9d1d970 | ||
{ | ||
...Custom Request Body Parameters | ||
} | ||
|
||
// RESPONSE | ||
202 ACCEPTED | ||
Operation-Location: /reports/f7cf8412-08ed-40c9-ac1b-296da9d1d970 | ||
{ | ||
"id": "f7cf8412-08ed-40c9-ac1b-296da9d1d970", | ||
"result": null | ||
} | ||
``` | ||
|
||
Once new long-running request posted, corresponding instance of running process created for tracking purpose. To access details about process and completeness status GET operation **MUST** be used. Such request will return current status of the background process along with the request parameters. | ||
|
||
- Status of long-running processing **MUST** be always returned via GET request with provided `id` of the asynchronous process | ||
|
||
``` | ||
// request to get details about already posted asynchronous request | ||
GET /reports/f7cf8412-08ed-40c9-ac1b-296da9d1d970 | ||
|
||
// RESPONSE | ||
200 OK | ||
{ | ||
"id": "f7cf8412-08ed-40c9-ac1b-296da9d1d970", | ||
"ref": "sps:report::f7cf8412-08ed-40c9-ac1b-296da9d1d970", | ||
"status": "RUNNING", | ||
"detail": "same as detail from bulk... maybe error message? or complex object?", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same questions on if details on errors should be some standard error format? definitely this answer should match between this and bulk updates. |
||
"result": null, | ||
"completenessDescription": "1 of 7", | ||
"createdDateTime": "2023-07-21T17:32:28.000Z", | ||
"createdBy": "user-xxxxx", | ||
"completedDateTime": "2023-07-21T17:32:28.000Z" | ||
} | ||
``` | ||
|
||
## Polling (Endpoint with Status Monitor) | ||
|
||
Do we need to support this? https://github.com/microsoft/api-guidelines/blob/vNext/azure/ConsiderationsForServiceDesign.md#long-running-operations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
scoping this to just polling right now.