API¶
proTES implements the GA4GH Task Execution Service (TES)
API, version 1.1
(specification),
at /ga4gh/tes/v1/. A deployment's Swagger UI (/ga4gh/tes/v1/ui/) shows
the endpoints and lets you try them; the specification is served at
/ga4gh/tes/v1/openapi.json. All endpoints except GET /service-info, the
specification and the Swagger UI require an access token (see Access
control).
| Endpoint | Description |
|---|---|
GET /service-info |
The service info of the deployment (see Service info). |
POST /tasks |
Create a task: proTES forwards it to a TES instance (see Tasks) and returns its own identifier of the task. |
GET /tasks |
List the caller's tasks, newest first, one page at a time (page_size, at most max_page_size of the config, and max_page_size_full tasks, of at most max_page_bytes_full bytes, for the view FULL; page_token from next_page_token of the previous page, which is empty on the last page), optionally only those whose name starts with name_prefix (taken literally; matched against the name of the task as submitted, before plugins may have renamed it), by state, or by tags (tag_key and tag_value, in pairs, taken literally: a key without a value, or with an empty one, matches any value of that tag; a task must match all pairs; more values than keys are rejected with 400 Bad Request; needs MongoDB 5.0 or later). |
GET /tasks/{id} |
Get a task of the caller, with its state as last tracked from the TES instance. |
GET /tasks/{id}/provenance |
proTES extension: get the provenance of a task, for its owner and for admins (see Provenance). |
GET /usage |
proTES extension: get the resources that the tasks of each user used, for admins, if accounting is enabled (see Usage). |
GET /plugins |
proTES extension (FOCA's plugin listing): list the plugins and presets that the caller may choose for its tasks, and the limits, for users; the default pipeline only for callers who may choose pipelines (see Choices of clients). |
GET /plugins/{plugin_id} |
proTES extension: describe a plugin that the caller may choose (404 Not Found otherwise). |
POST /tasks/{id}:cancel |
Cancel a task of the caller that has not finished yet (also in state UNKNOWN, e.g., not tracked yet), at the TES instance that runs it; the task is then in state CANCELING until the TES instance reports its final state (usually CANCELED), or answers that it no longer has the task (404 or 410; then CANCELED). Meanwhile, the task stays CANCELING, also while the TES instance is unavailable, until the first poll after polling.max_cancel_time seconds (default 3600; then SYSTEM_ERROR, and it is no longer tracked; see Task tracking); finished tasks are left as they are, also tasks that finish while they are canceled (their final state is kept), and tasks that the TES instance refuses to cancel as they have finished there (200; proTES stores their final state with the next poll). If a TES instance refuses to cancel a task that it hasn't finished, the task stays as it is (502 Bad Gateway). Unfinished tasks whose identifier at their TES instance is unknown (e.g., while they are being forwarded, or if forwarding failed unexpectedly) can't be canceled (409 Conflict). |
Only the owner of a task, the user who created it, can read and cancel it
(see Task ownership). Admins can manage
the access control rules at runtime through FOCA's permissions API at
/admin/access-control/permissions (see Access
control).
GET /tasks and GET /tasks/{id} return the views MINIMAL (the default;
identifier and state), BASIC (without the contents of inputs, the system
logs and the executors' standard output and error) and FULL (view), as
the TES specification describes. The view FULL has the logs of the TES
instance once the task has finished, as proTES gets them once then: earlier, it
has none, and if that one request fails (also for responses over
custom.tes.max_response_size, 10 MiB by default), the task
stays without them. The final state appears together with them. proTES
stores at most max_log_size of them per task, and keeps the end of longer ones
(see Tasks). Times (creation_time, and start_time
and end_time of proTES's log of a task) are in UTC, in RFC 3339 format.
Tasks¶
For POST /tasks, proTES:
- stores the task as received, with a new identifier
(see Tasks for its format) and its
creation_time(tasks that setcreation_time, which the TES specification marks read-only, are rejected with400 Bad Request, as are tasks with credentials in the URLs of inputs or outputs, unless proTES is configured to remove them, and tasks with a path over 4096 bytes (the value ofPATH_MAXon Linux;pathof inputs and outputs,path_prefix,volumes, andworkdir,stdin,stdoutandstderrof executors); tasks with inline contents of inputs overmax_inline_contentare rejected with413 Content Too Large: see Tasks); - runs the pipeline of plugins, which may change the task
and select the TES instances to try and their order (by default, in random
order; routing by the distance to the input data and FOCA's ordered
failover need an explicit pipeline, see Plugins);
a plugin may reject the task (with
its status, e.g.,
403 Forbidden), a step whose plugins all fail fails the request (500 Internal Server Error), tasks without TES instances fail with503 Service Unavailable, tasks that no selected TES instance can run unchanged (see TES versions) with400 Bad Request, and tasks whose inline contents plugins make too large with413 Content Too Large; none of these is kept; - forwards the task to the first of these TES instances that accepts it,
after the plugins of the
forwardphase, and returns its own identifier of the task (plugins may change the response); if no TES instance accepts it (withinplugins.defaults.forward_timeout), the request fails with503 Service Unavailable, and the task is not kept (it is deleted, with its owner's roles on it). Each TES instance gets its own copy of the task, in its TES version (see TES versions), without tags undergateway., with the credentials of proTES for it (see Credentials of TES instances), in a single request; the next TES instance is tried only if a TES instance certainly did not accept the task (see TES instances). If a TES instance may have accepted it without confirming it (e.g., the response timed out), the task is not sent to other TES instances, its state is set toSYSTEM_ERROR, and the request fails with502 Bad Gateway: the task may run at that TES instance, but proTES can neither track nor cancel it. Once a TES instance accepted the task, proTES stores the task with its TES instance and the remote identifier, and then with the state that the TES instance reports for it (it staysUNKNOWNif the state can't be got); - tracks the task at the TES instance in the background (a Celery worker
polls its state until it has finished; see Tasks),
and updates its state and logs; it gets the finished task once in the view
FULL, for the logs of the TES instance.
proTES keeps the task as received (task_original) as well as the task as
forwarded; the TES instance and the remote identifier of the task are in its
gateway tags (gateway.backend and gateway.backend_task_id, see below).
Since the move to plugins, proTES no longer records them in the logs of tasks
(logs[].metadata.forwarded_to, an array of objects in the string map
metadata, which the TES specification doesn't allow), and serves tasks
stored by earlier versions without them (see
Upgrading).
Gateway tags¶
proTES adds tags to each new task (FOCA's gateway tags, under the reserved
prefix plugins.tags.prefix, gateway. by default), served with the task in
the views BASIC and FULL, besides the client's own tags:
| Tag | Value | Added |
|---|---|---|
gateway.pipeline_source |
default, preset:<name> or client |
when the task is stored |
gateway.pipeline_hash |
sha256: hash of the resolved pipeline |
when the task is stored |
gateway.plugins |
the plugins that ran in the request and route phases, as id@version, comma-separated |
when the task is stored |
gateway.provenance |
the path of the task's provenance (/ga4gh/tes/v1/tasks/<id>/provenance) |
when the task is stored |
gateway.backend |
the URL of the TES instance that accepted the task (or may have) | after forwarding |
gateway.backend_task_id |
the identifier of the task at that TES instance, if it accepted it | after forwarding |
gateway.forwarded_at |
when the task was sent to it (RFC 3339, UTC) | after forwarding |
gateway.attempts |
the number of TES instances tried | after forwarding |
gateway.route |
the last attempts as compact JSON (url, outcome, reason) |
after forwarding |
gateway.route_truncated |
true if gateway.route leaves out attempts |
after forwarding |
Tracking a task doesn't change its tags. If tags can't be built (an internal error, which is logged), the task is created without them; its provenance is stored nevertheless.
Clients can't set these tags (400 Bad Request; only gateway.backends,
and gateway.pipeline if enabled, are theirs, see
Plugins), and plugins can't change them.
TES instances get tasks without any tag under the prefix. Clients that
submit a fetched task again drop the tags under the prefix first, except
their own choices. Tasks created by earlier versions have none.
Provenance¶
GET /tasks/{id}/provenance (a proTES extension) returns the provenance of
a task: the record that FOCA's plugin engine made when the task was created
and forwarded (see Task provenance), with
the builds of the plugins that ran (builds, by build hash) and the
resolved pipeline (pipeline.resolved), e.g., shortened:
{
"engine": {"foca": "0.22.0", "plugin_api": 1,
"app": {"name": "proTES", "version": "0.6.0"}},
"request_id": "4f3c...",
"pipeline": {"source": "default", "preset": null, "requested": null,
"resolved": [{"id": "route", "alternatives": ["..."]}],
"resolved_hash": "sha256:9a1e..."},
"plugins": {"sha256:77b0...": "foca.routing.ordered"},
"builds": {"sha256:77b0...": {"id": "foca.routing.ordered",
"distribution": "foca", "version": "0.22.0"}},
"executions": [{"step": "route", "phase": "route", "outcome": "ok"}],
"route": {"candidates_in": ["https://tes.example.org"],
"candidates_out": ["https://tes.example.org"]},
"selection": null,
"attempts": [{"number": 1, "backend": "https://tes.example.org",
"outcome": "accepted", "reason": null, "remote_id": "task-1",
"started_at": "2026-10-31T09:00:00.020Z", "duration_ms": 80.1}],
"final_reason": null
}
The owner of the task and admins may get it; everyone else gets
403 Forbidden, also for unknown tasks (see Access
control); admins get 404 Not Found for
unknown tasks. Tasks without provenance (e.g.,
created by earlier versions) give 404 Not Found. The record holds no
inputs, logs, IP addresses, tokens, header values or claims: plugins'
changes are recorded as paths and hashes only.
Usage¶
GET /usage (a proTES extension) returns the resources that the tasks of
each user used, as recorded when they finished, if accounting of resource
usage is enabled: per user
(user_id, the owner of the tasks; null for tasks without owner), the
number of tasks, those without known run time (untimed_tasks), the run
time in seconds, and the requested resources times the run time:
{
"recording": true,
"users": [
{"user_id": "alice", "tasks": 12, "untimed_tasks": 0,
"wall_seconds": 5400.0, "cpu_core_seconds": 10800.0,
"ram_gb_seconds": 21600.0, "disk_gb_seconds": 54000.0}
]
}
recording tells whether finishing tasks are recorded
(custom.accounting.enabled); stored records are served either way. A total
too large for a 64-bit float is the largest one (1.7976931348623157e+308),
as JSON has no infinity. The
query parameters limit the totals:
user_id: the tasks of one user only;sinceanduntil: the tasks that finished at or aftersinceand beforeuntil(date-times of RFC 3339, e.g.,2026-11-01T00:00:00Z; UTC without time zone), by the end of the task at its TES instance, or, if that is unknown, by when it was recorded. Other values, also other forms of ISO 8601 (e.g., a date without time) and leap seconds (:60), give400 Bad Request.
Only admins may get it (rule admins-get-usage); everyone else gets 403
Forbidden (see Access control). All users are
listed in one response, in the order of their identifiers.
Errors¶
Errors are problem details (with
title, status and detail; errors of the plugin engine and of task
limits also with problem_type, a URI in FOCA's or proTES' documentation), sent as application/json,
as the GA4GH
specification declares: 400 Bad Request for invalid requests (e.g.,
outputs with wildcards without path_prefix,
invalid tasks or query parameters, or invalid or reserved tags under
gateway.), 401 Unauthorized for requests
without a valid access token (with a Bearer challenge), 403 Forbidden for
users without the required role and for tasks of others or unknown tasks
(see Access control), 404 Not Found for tasks of the
caller deleted from the database, 409 Conflict for unfinished tasks
whose identifier at their TES instance is unknown, which can't be canceled,
413 Content Too Large for request bodies over the size
limit and tasks with inline contents
of inputs over max_inline_content (see
Tasks), 429 Too Many Requests for tasks of
users who have as many tasks as a task limit
allows (the limit is named in detail), the status of a plugin that rejected a
task, 500 Internal Server Error if all plugins of a step failed,
502 Bad Gateway if a TES instance did not confirm a request to create or
cancel a task, which it may have processed, or refused to cancel a task (see
Tasks),
503 Service Unavailable if no TES instance accepted a task (in time; it
is not kept), and 508 Loop Detected for tasks that passed proTES before
(see Plugins). The
mapping of exceptions to problem details is
exceptions in
pro_tes.exceptions.
The TES specification declares only the successful responses. The served
specification adds, as proTES extensions, 413 Content Too Large and 429
Too Many Requests to POST /tasks and 409 Conflict to POST /tasks/{id}:cancel, with the
schema ProblemDetails (cf.
additions.openapi.yaml),
as clients don't get these from TES servers in general; the operations are
otherwise those of the TES specification. The other errors are those of
any HTTP API, and are not declared.