Skip to content

Modelling wait_for_completion #1767

Open
@swallez

Description

@swallez

The problem

We have 16 endpoints that have a wait_for_completion parameter that instructs the ES cluster to run potentially lengthy operations in a blocking fashion or to run them asynchronously as a background task.

The response structure of these endpoints varies heavily depending on the value of this parameter. The default value for this parameter depends on the endpoint (most often true, but not always).

When wait_for_completion=true, the request blocks until the processing is finished, and the "normal" response body is then returned. When it's false, the request processing is started in the background on the ES cluster and some information about the background process is returned. The background response can vary, e.g. {"acknowledged": true} (snapshot-restore) or a task id { "task": "oTUltX4"} for ml-delete-job

The current state of the API specification is not optimal when it comes to supporting this feature, as having a single response structure requires to merge both normal and background properties in a single type, and consequently make them all optional.

Furthermore, as the ES documentation is generally sparse about the background response format, it is often forgotten in the spec and the focus is put on normal response properties, including making them required, which can cause issues (see elastic/elasticsearch-java#201).

Semantics of wait_for_completion

From a semantic perspective, endpoints with a wait_for_completion are endpoints that are "background-capable". We can consider them as the combination of a foreground endpoint that returns the normal (foreground) response, and a background endpoint that starts a task in the background and returns information about the background process.

Those two endpoints have the exact same request path, parameters and body, with the exception of wait_for_completion, and only differ by their response types.

Some client generators may decide to have a single endpoint whose response is the a union of both foreground and background response types, while some others may want to distinguish the two endpoints to avoid exposing a union whose active variant depends on the value set for wait_for_completion (that parameter would then be removed from the request structure and set internally by the endpoint functions).

For example in the case of the Java client, that second form would be used and the snapshot-restore endpoint would result in two functions:

  • restore(RestoreRequest): RestoreResponse (foreground, internally sets wait_for_completion=true)
  • restoreAsync(RestoreRequest): AcknowledgedResponse (background, internally sets wait_for_completion=false)

In TypeScript however, the first form with a single function would be used:

  • restore(RestoreRequest): RestoreResponse | AcknowledgedResponse

Proposal: the Backgroundable type

To correctly capture the two response structures and allow client generators to be able to generate two related endpoints, we suggest to introduce the Backgroundable type for the response body of background-capable endpoints:

type Backgroundable<Foreground, Background> = Foreground | Background

For example, the response of snapshot-restore is currently:

export class Response {
  body: { snapshot: SnapshotRestore }
}

It would become:

export class Response {
  body: Backgroundable<RestoreResponse, AckowledgedResponse>
}

export type RestoreResponse {
  snapshot: SnapshotRestore
}

wait_for_completion in a request and Backgroundable in a response should go hand in hand: one cannot be present without the other in an endpoint definition, and this can be enforced by model validation.

Of course naming is hard and better naming than Backgroundable is welcome 😉

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions