Skip to content

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.

FeatureGoJS/TSPythonJavaRustRuby
Client (enqueue, cancel, getJob)YesYesYesYesYesYes
Batch enqueueYesYesYesYesYesYes
Worker (poll, handlers, concurrency)YesYesYesYesYesYes
Enqueue middlewareYesYesYesYesYesYes
Execution middlewareYesYesYesYesYesYes
Workflows (chain, group, batch)YesYesYesYesYesYes
Graceful shutdownYesYesYesYesYesYes
Event emitterYesYesYesYesYesYes
Type safetyYesYesYesYesYesN/A

Package: github.com/openjobspec/ojs-go-sdk Requirements: Go 1.22+

Terminal window
go get github.com/openjobspec/ojs-go-sdk
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 := 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())
Terminal window
go test ./... -race -cover
go vet ./...

Package: @openjobspec/sdk Requirements: Node 18+

Terminal window
pnpm add @openjobspec/sdk
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}`);
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();
Terminal window
npm run build # tsc
npm test # vitest run
npm run test:watch # vitest (watch mode)
npm run lint # tsc --noEmit

Package: openjobspec Requirements: Python 3.11+

Terminal window
pip install openjobspec
import asyncio
from 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())
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()
Terminal window
pip install -e ".[dev]"
pytest # asyncio_mode = auto
mypy src/ # strict mode
ruff check . # linting

Package: com.openjobspec:ojs-sdk Requirements: Java 21+

<dependency>
<groupId>com.openjobspec</groupId>
<artifactId>ojs-sdk</artifactId>
<version>1.0.0</version>
</dependency>
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());
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.

Terminal window
mvn clean package
mvn test

Package: openjobspec Requirements: Rust 1.75+

Terminal window
cargo add openjobspec
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(())
}
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.

Terminal window
cargo build
cargo test
cargo clippy

Package: openjobspec Requirements: Ruby 3.2+

Terminal window
gem install openjobspec

Or in your Gemfile:

gem 'openjobspec'
require 'openjobspec'
client = OJS::Client.new(url: 'http://localhost:8080')
job = client.enqueue('email.send', ['user@example.com', 'welcome'])
puts "Enqueued: #{job.id}"
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.start

Uses stdlib only with no external dependencies.

Terminal window
bundle install
bundle exec rspec

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.