Run a job off-platform

Run a script on your own machine and record everything it writes as a single job execution on Labric.
View as Markdown

Most jobs run in a sandbox on Labric. Sometimes the script has to run somewhere else: on the PC attached to an instrument, on a machine inside your network, or from a scheduler you already operate. Off-platform executions cover that case. Your script opens an execution, tags its writes and uploads with the execution’s ID, and closes it when done. Labric then shows the run on the job page like any other execution, with the same provenance, so you can inspect what it produced and revert it as a unit.

Prerequisites

  • Python 3.9 or later with the SDK installed: pip install labric
  • An API key with the write scope, created under Settings > API Keys on platform.labric.co and exported as LABRIC_API_KEY

Start an execution

Open an execution before the script does any work. The response carries the job_execution_id that everything else in the run is tagged with.

from labric import Labric, StartJobExecutionSchema
client = Labric()
execution = client.jobs.start(
request=StartJobExecutionSchema(
job_name="Plate Reader Import",
timeout_minutes=30,
)
)
execution_id = execution.job_execution_id

job_name is the job the run is filed under. Labric creates it if it doesn’t exist, so the first run of a new script creates its job. Pass job_id instead to run under a job that already exists. Omit both and the run goes under a job called “Off-Platform Manual Job”.

timeout_minutes is a safety net. If the script crashes before closing the execution, Labric marks it failed after that long instead of leaving it running forever. Set it a little above the longest run you expect.

Write data and upload files

Pass job_execution_id on every write so the rows are attributed to this run:

client.tools.write(
target_type="table",
target_name="plate_reads",
data=records,
mode="create",
job_execution_id=execution_id,
)

Files work the same way. Uploading with job_execution_id stores the file as an artifact of the run:

with open("raw_export.csv", "rb") as f:
client.files.upload(file=f, job_execution_id=execution_id)

If you skip job_execution_id on a write, Labric still records it, but under a new execution of its own. Tagging is what turns a script’s separate calls into one run.

Close the execution

When the script finishes, close the execution as completed or failed. Both are final: closing twice with the same status is a no-op, and switching status afterwards is rejected.

client.jobs.close(execution_id, status="completed")

Putting it together

import csv
from labric import Labric, StartJobExecutionSchema
client = Labric()
execution = client.jobs.start(
request=StartJobExecutionSchema(job_name="Plate Reader Import", timeout_minutes=30)
)
execution_id = execution.job_execution_id
try:
with open("raw_export.csv", "r") as f:
records = list(csv.DictReader(f))
client.tools.write(
target_type="table",
target_name="plate_reads",
data=records,
mode="create",
job_execution_id=execution_id,
)
with open("raw_export.csv", "rb") as f:
client.files.upload(file=f, job_execution_id=execution_id)
except Exception:
client.jobs.close(execution_id, status="failed")
raise
client.jobs.close(execution_id, status="completed")

The run shows up on the job’s page in Jobs, with the rows it wrote and the file it uploaded.

Undo a run

If a run wrote bad data, revert it. This deletes every row the execution created in one transaction. Rows it updated or deleted can’t be restored and are listed as warnings in the result.

result = client.jobs.revert(execution_id)
print(result)

Instrument data without a script

If you only need to get files off an instrument that the Sync app can’t reach, you don’t need an execution at all. Upload with instrument_id instead, and the file is attached to that instrument so its triggers and parsers pick it up:

client.files.upload(file=f, instrument_id="your-instrument-id")