SuperJobs
Pre-alpha · Python 3.12+ · Interface under active development.
SuperJobs runs typed asynchronous jobs over NATS JetStream. Producers submit work; workers execute it and publish results and observations. Both share job definitions and payload types, so producers can use contracts independently of handler code.
Setup
From a repository checkout:
uv sync
Use a JetStream-enabled NATS server reachable from both the worker and
producer processes. These examples default to nats://localhost:4222.
To use another broker, set SUPERJOBS_NATS_URL in each process's environment.
Save the following four files together. In a larger application, package the contracts separately so producers can install them without worker dependencies.
Shared contract (my_contracts.py)
from dataclasses import dataclass
from superjobs import Job
@dataclass(frozen=True, slots=True, kw_only=True)
class ManifestRequest:
device_id: str
@dataclass(frozen=True, slots=True)
class ManifestResult:
revision: str
@dataclass(frozen=True, slots=True)
class ManifestEvent:
stage: str
MANIFEST_JOB = Job(
"examples.contract.manifest",
version="v1",
request=ManifestRequest,
result=ManifestResult,
event=ManifestEvent,
)
Handlers (my_handlers.py)
Define the handler once in a catalog that the worker consumes:
from superjobs import HandlerCatalog, JobContext
from my_contracts import (
MANIFEST_JOB,
ManifestEvent,
ManifestRequest,
ManifestResult,
)
handlers = HandlerCatalog()
@handlers.handler(MANIFEST_JOB)
async def manifest(
request: ManifestRequest,
context: JobContext[ManifestEvent],
) -> ManifestResult:
await context.emit(ManifestEvent(stage="validated"))
return ManifestResult(revision=f"{request.device_id}-r1")
JobContext lets the handler publish events, logs, and progress for its execution.
Worker (worker.py)
import asyncio
import os
from faststream.nats import NatsBroker
from superjobs import SuperJobs
from my_handlers import handlers
NATS_URL = os.environ.get("SUPERJOBS_NATS_URL", "nats://localhost:4222")
async def main() -> None:
jobs = SuperJobs(broker=NatsBroker(NATS_URL), handlers=handlers)
await jobs.serve()
if __name__ == "__main__":
asyncio.run(main())
serve() owns startup, waiting, and graceful shutdown for the worker process.
Producer (producer.py)
The producer imports the shared contract:
import asyncio
import os
from faststream.nats import NatsBroker
from superjobs import SuperJobs
from my_contracts import MANIFEST_JOB
NATS_URL = os.environ.get("SUPERJOBS_NATS_URL", "nats://localhost:4222")
async def main() -> None:
async with SuperJobs(broker=NatsBroker(NATS_URL)) as jobs:
client = jobs.client(MANIFEST_JOB)
handle = await client.submit(device_id="sensor-17")
result = await handle.result()
print(result.revision)
if __name__ == "__main__":
asyncio.run(main())
Run the worker and producer in two terminals against the same broker:
uv run python worker.py
uv run python producer.py
The producer prints sensor-17-r1. submit() returns a
handle to one execution; you can observe status, recorded observations, and
outcomes later or from another process. Details: docs/api.md.
Executions are delivered at least once, so make external side effects idempotent. Accepted work can outlive the submitting process. Retry and outage behavior: ADR 0005.
CLI (optional)
Install the CLI extra, then expose the same handler catalog the worker uses:
uv sync --extra cli
On the existing manifest handler in my_handlers.py, add cli="manifest" to
the decorator (same function body as above):
-@handlers.handler(MANIFEST_JOB)
+@handlers.handler(MANIFEST_JOB, cli="manifest")
myapp_cli.py:
from superjobs.cli import JobCLI
from my_handlers import handlers
def main() -> int:
return JobCLI(handlers=handlers).main()
if __name__ == "__main__":
raise SystemExit(main())
Remote submit uses the built-in NATS producer runtime. Optional default URL:
JobCLI(handlers=handlers, nats_url="nats://broker:4222"). Resolution order for
submit: --nats-url, then SUPERJOBS_NATS_URL, then JobCLI(nats_url=...), then
nats://localhost:4222.
With the NATS worker running:
uv run python myapp_cli.py submit manifest --device-id sensor-17 --wait
uv run python myapp_cli.py submit --nats-url nats://broker:4222 manifest --device-id sensor-17 --wait
For local execution without a broker:
uv run python myapp_cli.py run manifest --device-id sensor-17
When packaging the app, map main() through a [project.scripts] entry.
Input forms, exit codes,
composition, resources, and contracts-only CLIs:
docs/cli.md. Runnable multi-package layout:
examples/contract_interface/.
For tests without a broker, use InMemoryTransport; see
docs/development.md.
Further API detail: docs/api.md. Domain terms: CONTEXT.md. Checks and CI: docs/development.md. Measured results: docs/verification.md.
Metadata
Release files for superjobs 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| superjobs-0.1.0.tar.gz | 69.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| superjobs-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 170.5 kB
Release files / superjobs-0.1.0.tar.gz
| Download URL | superjobs-0.1.0.tar.gz |
|---|---|
| Size | 69.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
df2ce1808ec4c60d15f35c1d67e054031290c3444521fe0032b8508f0a016ee6
|
|
BLAKE2b-256 checksum How to use checksums |
a621c1a2f9177011d3725fbf94119772bc346fb08c4ff3de01115bd120a3f455
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / superjobs-0.1.0-py3-none-any.whl
| Download URL | superjobs-0.1.0-py3-none-any.whl |
|---|---|
| Size | 100.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5f70a0f7d2caae186ae0ed216575703ee017787a5ae52ecce00caade47f6661e
|
|
BLAKE2b-256 checksum How to use checksums |
1706c753ccd7cb6fc654c7c853121ecc26b4c3a3942ef5abb1ee9df4d840aa06
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|