Distributed Workers¶
Strata Notebook can dispatch individual cells to remote machines via the executor protocol. A worker is any HTTP endpoint that accepts cell source code and inputs, runs them, and returns the outputs. You bring the compute, Strata handles the routing, serialization, and caching.
How It Works¶
┌─────────────────────┐ multipart POST ┌──────────────────────┐
│ Strata Notebook │ ──────────────────► │ Worker (HTTP) │
│ (orchestrator) │ │ remote_executor.py │
│ │ ◄────────────────── │ │
│ routes cell to │ gzipped bundle │ runs harness.py │
│ @worker annotation │ (outputs + blobs) │ returns results │
└─────────────────────┘ └──────────────────────┘
- You annotate a cell with
# @worker my-gpu - Strata looks up
my-gpuin the notebook's[[workers]]config - The cell source + serialized input variables are sent as a multipart HTTP POST
- The worker runs the cell in a subprocess and returns outputs as a gzipped bundle
- Strata stores the outputs as artifacts, cache hits work identically to local cells
Registering Workers¶
Add workers from the Workers panel in the sidebar. Give each one a name (used in @worker annotations), the executor endpoint URL, and, optionally, a runtime_id that pins provenance so cache hits are stable across worker upgrades.
The result lands in notebook.toml as [[workers]] entries:
[[workers]]
name = "my-gpu"
backend = "executor"
runtime_id = "my-gpu-a10g"
[workers.config]
url = "https://my-worker.example.com/v1/execute"
transport = "http"
| Field | Description |
|---|---|
name |
The name used in @worker annotations |
backend |
Always "executor" for HTTP workers |
runtime_id |
Optional stable identifier for provenance (changing this invalidates cache) |
config.url |
The HTTP endpoint for the executor protocol |
config.transport |
"http" for direct push, "signed" for pull-model with signed URLs |
Register as many workers as you need, each cell picks its target independently. An example notebook with two workers ends up looking like:
[[workers]]
name = "df-cluster"
backend = "executor"
runtime_id = "df-cluster"
[workers.config]
url = "https://my-datafusion.fly.dev/v1/execute"
transport = "http"
[[workers]]
name = "gpu"
backend = "executor"
runtime_id = "gpu-a10g"
[workers.config]
url = "https://my-gpu-worker.modal.run/v1/execute"
transport = "http"
Running a Worker¶
Strata ships a reference executor as the strata-worker console script:
This starts a FastAPI server that:
- Accepts multipart cell execution requests at
/v1/execute - Runs cells via the same
harness.pysubprocess as local execution - Returns outputs as a gzipped bundle
- Exposes
/healthfor monitoring
The worker runs cells using its own Python environment: whatever packages are installed in the worker's interpreter are available to cells. This is how you provide GPU libraries (torch, sentence-transformers) or data engines (datafusion) without installing them locally. Install your workload dependencies before launching strata-worker.
Deploying to Fly.io (CPU worker)¶
FROM python:3.12-slim AS builder
RUN apt-get update && apt-get install -y --no-install-recommends \
curl build-essential git ca-certificates && \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal && \
rm -rf /var/lib/apt/lists/*
ENV PATH="/root/.cargo/bin:$PATH"
RUN pip install --no-cache-dir \
"strata-notebook @ git+https://github.com/bearing-research/strata.git@main" \
"datafusion>=42" \
"pandas>=2" \
"pyarrow>=18"
FROM python:3.12-slim
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
EXPOSE 8080
CMD ["strata-worker", "--host", "0.0.0.0", "--port", "8080"]
Deploy with fly deploy. Register the Fly URL as a worker via the Workers panel.
Deploying to Modal (GPU worker)¶
import modal
gpu_image = (
modal.Image.debian_slim(python_version="3.12")
.apt_install("curl", "build-essential", "git", "ca-certificates")
.run_commands(
"curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal",
)
.env({"PATH": "/root/.cargo/bin:/usr/local/bin:/usr/bin:/bin"})
.pip_install(
"maturin>=1.5",
"fastapi>=0.115", "uvicorn>=0.30", "httpx>=0.27",
"python-multipart>=0.0.9",
"pyarrow>=18.0.0", "pandas>=2.0.0", "numpy>=1.26.0",
"torch>=2.3", "sentence-transformers>=3.0", "scikit-learn>=1.5",
"strata-notebook @ git+https://github.com/bearing-research/strata.git@main",
)
)
app = modal.App("my-gpu-worker", image=gpu_image)
@app.function(gpu="A10G", scaledown_window=60)
@modal.asgi_app()
def gpu_executor():
from strata.notebook.remote_executor import create_notebook_executor_app
return create_notebook_executor_app()
Deploy with modal deploy worker.py. The printed URL becomes the worker's config.url.
Using Workers in Cells¶
Annotate any cell with # @worker <name>:
# @name Embed Abstracts
# @worker gpu
# @timeout 300
embeddings = model.encode(abstracts, batch_size=256)
The worker annotation is the only change needed, the cell code itself is identical to what you'd write for local execution. If the worker has the right packages installed, it just works.
Precedence¶
If multiple levels define a worker, the most specific wins:
# @worker Xannotation in the cell source (highest)- Cell-level worker override (from the cell's config)
- Notebook-level worker default (from the Workers panel)
Caching¶
Remote execution results are cached identically to local cells. The provenance hash includes the worker's runtime_id, so:
- Same code + same inputs + same worker = cache hit (instant, no remote call)
- Changing the worker (e.g., switching from
gpu-a10gtogpu-h100) invalidates the cache for that cell
Local Development¶
For local testing without cloud deployment, run multiple workers on different ports:
# Terminal 1: DataFusion worker
uv run --with datafusion strata-worker --port 9000
# Terminal 2: GPU worker (with ML packages)
uv run --with torch --with sentence-transformers strata-worker --port 9001
Register both in the Workers panel pointing at http://127.0.0.1:9000/v1/execute and http://127.0.0.1:9001/v1/execute during development. Swap to cloud URLs when deploying, cells using @worker gpu move over without any code change.
Health Checks¶
Every worker exposes GET /health:
{
"status": "healthy",
"capabilities": {
"protocol_versions": ["v1"],
"transform_refs": ["notebook_cell@v1"],
"features": {
"notebook_protocol_version": "notebook-cell-v1",
"output_format": "notebook-output-bundle@v1"
}
},
"uptime_seconds": 42.5,
"active_executions": 0
}
The notebook UI shows worker health status as a badge next to cells that use that worker.
Live Status¶
When a cell dispatches to a remote worker, the UI shows a pulsing "dispatching → my-gpu" badge during execution. After completion, the worker name and transport type appear in the cell metadata.