SDKs
Six official SDKs cover the most popular programming languages. All SDKs follow the same structure and provide the same capabilities: a client for producing jobs, a worker for consuming them, middleware chains, and workflow helpers.
SDK feature matrix
Section titled “SDK feature matrix”| Feature | Go | JS/TS | Python | Java | Rust | Ruby |
|---|---|---|---|---|---|---|
| Client (enqueue, cancel, getJob) | Yes | Yes | Yes | Yes | Yes | Yes |
| Batch enqueue | Yes | Yes | Yes | Yes | Yes | Yes |
| Worker (poll, handlers, concurrency) | Yes | Yes | Yes | Yes | Yes | Yes |
| Enqueue middleware | Yes | Yes | Yes | Yes | Yes | Yes |
| Execution middleware | Yes | Yes | Yes | Yes | Yes | Yes |
| Workflows (chain, group, batch) | Yes | Yes | Yes | Yes | Yes | Yes |
| Graceful shutdown | Yes | Yes | Yes | Yes | Yes | Yes |
| Event emitter | Yes | Yes | Yes | Yes | Yes | Yes |
| Type safety | Yes | Yes | Yes | Yes | Yes | N/A |
Go SDK
Section titled “Go SDK”Package: github.com/openjobspec/ojs-go-sdk
Requirements: Go 1.22+
go get github.com/openjobspec/ojs-go-sdkClient example
Section titled “Client example”package main
import ( "context" "fmt" ojs "github.com/openjobspec/ojs-go-sdk")
func main() { client := ojs.NewClient(ojs.ClientConfig{ URL: "http://localhost:8080", })
job, err := client.Enqueue(context.Background(), "email.send", []any{"user@example.com", "welcome"}, ) if err != nil { panic(err) } fmt.Printf("Enqueued: %s\n", job.ID)}Worker example
Section titled “Worker example”worker := ojs.NewWorker(ojs.WorkerConfig{ URL: "http://localhost:8080", Queues: []string{"default"}, Concurrency: 10,})
worker.Handle("email.send", func(ctx ojs.JobContext) error { to := ctx.Args[0].(string) template := ctx.Args[1].(string) return sendEmail(to, template)})
worker.Start(context.Background())Testing
Section titled “Testing”go test ./... -race -covergo vet ./...JavaScript / TypeScript SDK
Section titled “JavaScript / TypeScript SDK”Package: @openjobspec/sdk
Requirements: Node 18+
pnpm add @openjobspec/sdkClient example
Section titled “Client example”import { OJSClient } from '@openjobspec/sdk';
const client = new OJSClient({ url: 'http://localhost:8080' });
const job = await client.enqueue('email.send', [ 'user@example.com', 'welcome',]);console.log(`Enqueued: ${job.id}`);Worker example
Section titled “Worker example”import { OJSWorker } from '@openjobspec/sdk';
const worker = new OJSWorker({ url: 'http://localhost:8080', queues: ['default'], concurrency: 10,});
worker.handle('email.send', async (ctx) => { const [to, template] = ctx.args; await sendEmail(to, template); return { delivered: true };});
process.on('SIGINT', () => worker.stop());await worker.start();Testing
Section titled “Testing”npm run build # tscnpm test # vitest runnpm run test:watch # vitest (watch mode)npm run lint # tsc --noEmitPython SDK
Section titled “Python SDK”Package: openjobspec
Requirements: Python 3.11+
pip install openjobspecClient example
Section titled “Client example”import asynciofrom openjobspec import OJSClient
async def main(): client = OJSClient(url="http://localhost:8080") job = await client.enqueue("email.send", ["user@example.com", "welcome"]) print(f"Enqueued: {job.id}")
asyncio.run(main())Worker example
Section titled “Worker example”from openjobspec import OJSWorker
worker = OJSWorker( url="http://localhost:8080", queues=["default"], concurrency=10,)
@worker.handle("email.send")async def handle_email(ctx): to, template = ctx.args await send_email(to, template) return {"delivered": True}
worker.start()Testing
Section titled “Testing”pip install -e ".[dev]"pytest # asyncio_mode = automypy src/ # strict moderuff check . # lintingJava SDK
Section titled “Java SDK”Package: com.openjobspec:ojs-sdk
Requirements: Java 21+
<dependency> <groupId>com.openjobspec</groupId> <artifactId>ojs-sdk</artifactId> <version>1.0.0</version></dependency>Client example
Section titled “Client example”import com.openjobspec.OJSClient;import com.openjobspec.Job;
var client = OJSClient.create("http://localhost:8080");var job = client.enqueue("email.send", List.of("user@example.com", "welcome"));System.out.println("Enqueued: " + job.id());Worker example
Section titled “Worker example”import com.openjobspec.OJSWorker;
var worker = OJSWorker.builder() .url("http://localhost:8080") .queues(List.of("default")) .concurrency(10) .build();
worker.handle("email.send", ctx -> { String to = (String) ctx.args().get(0); String template = (String) ctx.args().get(1); sendEmail(to, template); return Map.of("delivered", true);});
worker.start();Uses Java 21 records and has zero required dependencies.
Testing
Section titled “Testing”mvn clean packagemvn testRust SDK
Section titled “Rust SDK”Package: openjobspec
Requirements: Rust 1.75+
cargo add openjobspecClient example
Section titled “Client example”use openjobspec::OJSClient;
#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let client = OJSClient::new("http://localhost:8080");
let job = client .enqueue("email.send", &["user@example.com", "welcome"]) .await?;
println!("Enqueued: {}", job.id); Ok(())}Worker example
Section titled “Worker example”use openjobspec::{OJSWorker, JobContext};
#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let mut worker = OJSWorker::builder() .url("http://localhost:8080") .queues(&["default"]) .concurrency(10) .build()?;
worker.handle("email.send", |ctx: JobContext| async move { let to = ctx.args[0].as_str().unwrap(); let template = ctx.args[1].as_str().unwrap(); send_email(to, template).await?; Ok(serde_json::json!({"delivered": true})) });
worker.start().await}Built on tokio and serde for full async support and type safety.
Testing
Section titled “Testing”cargo buildcargo testcargo clippyRuby SDK
Section titled “Ruby SDK”Package: openjobspec
Requirements: Ruby 3.2+
gem install openjobspecOr in your Gemfile:
gem 'openjobspec'Client example
Section titled “Client example”require 'openjobspec'
client = OJS::Client.new(url: 'http://localhost:8080')job = client.enqueue('email.send', ['user@example.com', 'welcome'])puts "Enqueued: #{job.id}"Worker example
Section titled “Worker example”require 'openjobspec'
worker = OJS::Worker.new( url: 'http://localhost:8080', queues: ['default'], concurrency: 10)
worker.handle('email.send') do |ctx| to, template = ctx.args send_email(to, template) { delivered: true }end
worker.startUses stdlib only with no external dependencies.
Testing
Section titled “Testing”bundle installbundle exec rspecBuilding your own SDK
Section titled “Building your own SDK”If your language is not listed above, you can build your own SDK. The OJS specification is designed to make SDK implementation straightforward. See the Implement an SDK guide for a detailed walkthrough.
The key insight: OJS SDKs are thin HTTP wrappers. All intelligence (retry logic, scheduling, state management) lives in the server. Your SDK just needs to make HTTP requests and provide a nice API for registering handlers and polling for work.