Skip to main content

OpenSAFELY job runner

A job runner is a service that encapsulates:

  • the task of checking out an OpenSAFELY study repo;
  • executing actions defined in its project.yaml configuration file when requested via a jobs queue; and
  • storing its results in a particular locations.

Quickrefs:

End users will find more information in the OpenSAFELY documentation.

Operating principles

In production, this software runs as a loop on a secure server within the infrastructure of the primary data provider. It polls an OpenSAFELY job server, looking for requests to run jobs.

Jobs belong to a workspace. This describes the git repo containing the OpenSAFELY-compliant project under execution; the git branch, and kind of database to use. The workspace also acts as a kind of namespace for partitioning outputs of its jobs.

An OpenSAFELY-compliant repo must provide a project.yaml file which describes how a requested job should be converted into a command (& arguments) that can be run in a subprocess on the secure server. It incorporates the idea of dependencies, so an action that generates a chart might depend on an action that extracts data from the database for that chart. See the Actions reference for more information.

An action can define outputs; these are persisted on disk and made available to subsequent actions in the workspace, and users who have permission to log into the server and view the raw files.

The runner takes care of executing dependencies in order. By default, it skips re-running a dependency whose previous run produced output that still exists in the production environment. The runner also reports status back to the job server, redacting possibly-sensitive information.

The runner is bundled as part of the opensafely-cli tool so users can test their actions locally.

Job structure

The job server serves jobs as JSON in the following format. First, a job must belong to a workspace:

{
    "workspace": {
        "name": "my workspace",
        "repo": "https://github.com/opensafely/job-integration-tests",
        "branch": "master",
        "db": "full"
    }
}

Possible values for "db" are "full", "slice", and "dummy".

A workspace is a way of associating jobs related to a given combination of branch, repository and database. To enqueue a job, a client POSTs JSON like this:

{
    "backend": "tpp",
    "action_id": "do_thing",
    "workspace_id": 1
}

Consuming jobs

A job runner is service installed on a machine that has access to a given backend. It receives jobs from the server and consumes those whose backend value matches the value of the current BACKEND environment variable.

It must also define three environment variables which are an RFC1838 connection URL; these correspond to the db requested in the job's workspace definition, and as such are named FULL_DATABASE_URL, SLICE_DATABASE_URL, and DUMMY_DATABASE_URL.

When a job is found, the following happens:

  • The corresponding repo is fetched. Private repos are accessed using the PRIVATE_REPO_ACCESS_TOKEN supplied in the environment.
  • Its project.yaml is parsed:
    • Individual actions are extracted from this file
    • A dependency graph is calculated for the requested action; for example, an action might depend on three previous actions before it can be run
    • Each action in the graph is checked to see if it needs to be run
      • Actions that either: (a) already have output generated from a previous run; (b) are currently running; (c) failed on their last run do not need to be run
    • If a dependency has failed, then the requested action fails
    • If the dependency needs to be run, a new job is pushed to the queue, and the current job is postponed
    • If an action has no dependencies needing to be run, then its docker run is executed
    • On completion, a status code and message are reported back to the job server. On success, a list of output file locations are also posted. On failure, the message has any potentially-sensitive information redacted, and is associated with a unique string so that a user with requisite permissions can log into the production environment and examine the docker logs for the full error.

Output locations

Every action defines a list of outputs which are persisted to a permanent storage location. The project author must categorise these outputs as either highly_sensitive or moderately_sensitive. Any pseudonymised data which may be highly disclosive (e.g. without low number redaction) should be classed as highly_sensitive; data which the author believes could be released following review should be classed as moderately_sensitive. This design allows tiered levels of permissions for collaborators to review data outputs. For example, the study author would usually have access to highly_sensitive material for debugging; but other collaborators could have access to moderately_sensitive data to prepare it for release (for which it is planned to add a minimally_sensitive category).

Outputs are therefore persisted to filesystem paths according to the following environment variables:

# A location where cohort CSVs (one row per patient) should be
# stored. This folder must exist.
HIGH_PRIVACY_STORAGE_BASE=/home/opensafely/high_security

# A location where script outputs (some for publication) should be
# stored
MEDIUM_PRIVACY_STORAGE_BASE=/tmp/outputs/medium_security

Project.yaml

A valid project file looks like this:

version: "3.0"

expectations:
  population_size: 1000

actions:

  generate_study_population:
    run: cohortextractor:latest generate_cohort --study-definition study_definition
    outputs:
      highly_sensitive:
        cohort: output/input.csv

  run_model:
    run: stata-mp:latest analysis/model.do
    needs: [generate_study_population]
    outputs:
      moderately_sensitive:
        model: models/cox-model.txt
        figure: figures/survival-plot.png

See the project pipeline documentation for a detailed description of the project.yaml setup.

Local actions development

The cohortextractor command-line tool imports this library, and implements the action-parsing-and-running functionality as a series of synchronous docker commands, rather than asynchronously via the job queue.

For developers

Please see the additional information.

Metadata

Release files for opensafely-jobrunner 2.52.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for opensafely-jobrunner 2.52.4
File Size Uploaded Provenance
opensafely-jobrunner-2.52.4.tar.gz 70.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for opensafely-jobrunner 2.52.4
File Interpreter ABI Platform
opensafely_jobrunner-2.52.4-py3-none-any.whl Python 3 none any Details

Total release size: 153.6 kB

Release files / opensafely-jobrunner-2.52.4.tar.gz

Download URL opensafely-jobrunner-2.52.4.tar.gz
Size 70.9 kB
Tags Source
SHA-256 checksum
How to use checksums
917770d7f20bc0052d5e5854fbca28db4c631850dfa070f7d9d51a004ad42881
BLAKE2b-256 checksum
How to use checksums
85ddccbdce773909d8dc71fba97bae56e6526bfee57842e777202970c7703f81
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.0 CPython/3.9.13

Release files / opensafely_jobrunner-2.52.4-py3-none-any.whl

Download URL opensafely_jobrunner-2.52.4-py3-none-any.whl
Size 82.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7d8aecca94102915366305cb7aa6a96bec44bca867070c83324664ad9ed3750d
BLAKE2b-256 checksum
How to use checksums
44020134dc59d53b5fd266f077f72656974d22214d0899bcae9685f9927f57e4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.0 CPython/3.9.13

Security for opensafely-jobrunner 2.52.4

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

2.52.4 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page