{"id":45579886,"url":"https://github.com/openjobspec/ojs-backend-redis","last_synced_at":"2026-02-28T17:07:56.624Z","repository":{"id":338056536,"uuid":"1155817366","full_name":"openjobspec/ojs-backend-redis","owner":"openjobspec","description":"Reference OJS backend implementation using Redis. Written in Go.","archived":false,"fork":false,"pushed_at":"2026-02-23T09:45:01.000Z","size":653,"stargazers_count":0,"open_issues_count":6,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-23T18:07:23.195Z","etag":null,"topics":["background-jobs","go","golang","job-queue","job-server","ojs","openjobspec","redis"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/openjobspec.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-11T23:55:27.000Z","updated_at":"2026-02-16T21:24:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/openjobspec/ojs-backend-redis","commit_stats":null,"previous_names":["openjobspec/ojs-backend-redis"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/openjobspec/ojs-backend-redis","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openjobspec%2Fojs-backend-redis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openjobspec%2Fojs-backend-redis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openjobspec%2Fojs-backend-redis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openjobspec%2Fojs-backend-redis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/openjobspec","download_url":"https://codeload.github.com/openjobspec/ojs-backend-redis/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openjobspec%2Fojs-backend-redis/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29943809,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-28T13:49:17.081Z","status":"ssl_error","status_checked_at":"2026-02-28T13:48:50.396Z","response_time":90,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["background-jobs","go","golang","job-queue","job-server","ojs","openjobspec","redis"],"created_at":"2026-02-23T11:41:25.379Z","updated_at":"2026-02-28T17:07:56.250Z","avatar_url":"https://github.com/openjobspec.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ojs-backend-redis\n\n![CI](https://github.com/openjobspec/ojs-backend-redis/actions/workflows/ci.yml/badge.svg)\n![Conformance](https://github.com/openjobspec/ojs-backend-redis/raw/main/.github/badges/conformance.svg)\n![Security](https://github.com/openjobspec/ojs-backend-redis/actions/workflows/security.yml/badge.svg)\n\nA Redis-backed implementation of the [OpenJobSpec (OJS)](https://github.com/openjobspec) specification — a standard interface for distributed job queues and workflow orchestration. This backend gives you a production-ready job server with priority queuing, retries, scheduling, cron jobs, workflows, and dead letter handling, all powered by Redis.\n\n## Key Features\n\n- **Full OJS compliance** — Passes conformance levels 0–4 with 17 supported capabilities\n- **Priority queuing** — Jobs are ordered by priority (-100 to 100) within each queue\n- **Retry policies** — Exponential, linear, and constant backoff with jitter and non-retryable error patterns\n- **Scheduled jobs** — Delay execution until a specific time\n- **Cron scheduling** — Register recurring jobs with standard cron expressions and timezone support\n- **Workflows** — Chain (sequential), group (parallel), and batch execution with callbacks\n- **Dead letter queue** — Inspect, retry, or delete failed jobs that have exhausted retries\n- **Job deduplication** — Unique policies with configurable conflict resolution\n- **Queue management** — Pause/resume queues, view per-queue statistics\n- **Batch enqueue** — Atomically submit multiple jobs in a single request\n- **Graceful shutdown** — Clean signal handling with in-flight request draining\n\n## Prerequisites\n\n- **Go** 1.23 or later\n- **Redis** 7.x\n- **Docker** and **Docker Compose** (optional, for containerized setup)\n\n## Installation\n\nClone the repository and build:\n\n```bash\ngit clone https://github.com/openjobspec/ojs-backend-redis.git\ncd ojs-backend-redis\nmake build\n```\n\nThis compiles the server binary to `bin/ojs-server`.\n\n## Quick Start\n\n### Option 1: Docker Compose (recommended)\n\nStart both Redis and the OJS server with a single command:\n\n```bash\nmake docker-up\n```\n\nThe server will be available at `http://localhost:8080`. To stop:\n\n```bash\nmake docker-down\n```\n\n### Option 2: Run locally\n\nStart a Redis instance, then run the server:\n\n```bash\n# Start Redis (if not already running)\nredis-server \u0026\n\n# Run the OJS server\nmake run\n```\n\n### Verify it's working\n\n```bash\ncurl http://localhost:8080/ojs/v1/health\n```\n\n## Usage Examples\n\n### Enqueue a job\n\n```bash\ncurl -X POST http://localhost:8080/ojs/v1/jobs \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"type\": \"email.send\",\n    \"args\": [{\"to\": \"user@example.com\", \"subject\": \"Hello\"}],\n    \"options\": {\n      \"queue\": \"default\",\n      \"priority\": 10\n    }\n  }'\n```\n\n### Fetch a job (as a worker)\n\n```bash\ncurl -X POST http://localhost:8080/ojs/v1/workers/fetch \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"queues\": [\"default\"],\n    \"worker_id\": \"worker-1\"\n  }'\n```\n\n### Acknowledge job completion\n\n```bash\ncurl -X POST http://localhost:8080/ojs/v1/workers/ack \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"job_id\": \"\u003cjob-id\u003e\",\n    \"worker_id\": \"worker-1\",\n    \"result\": {\"status\": \"delivered\"}\n  }'\n```\n\n### Report job failure\n\n```bash\ncurl -X POST http://localhost:8080/ojs/v1/workers/nack \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"job_id\": \"\u003cjob-id\u003e\",\n    \"worker_id\": \"worker-1\",\n    \"error\": \"connection timeout\"\n  }'\n```\n\n### Register a cron job\n\n```bash\ncurl -X POST http://localhost:8080/ojs/v1/cron \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"name\": \"daily-report\",\n    \"schedule\": \"0 9 * * *\",\n    \"timezone\": \"America/New_York\",\n    \"type\": \"reports.generate\",\n    \"queue\": \"reports\"\n  }'\n```\n\n### Create a workflow (chain)\n\n```bash\ncurl -X POST http://localhost:8080/ojs/v1/workflows \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"type\": \"chain\",\n    \"steps\": [\n      {\"type\": \"extract.data\", \"queue\": \"etl\"},\n      {\"type\": \"transform.data\", \"queue\": \"etl\"},\n      {\"type\": \"load.data\", \"queue\": \"etl\"}\n    ]\n  }'\n```\n\n### Batch enqueue\n\n```bash\ncurl -X POST http://localhost:8080/ojs/v1/jobs/batch \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"jobs\": [\n      {\"type\": \"email.send\", \"args\": [{\"to\": \"a@example.com\"}], \"options\": {\"queue\": \"default\"}},\n      {\"type\": \"email.send\", \"args\": [{\"to\": \"b@example.com\"}], \"options\": {\"queue\": \"default\"}}\n    ]\n  }'\n```\n\n## API Reference\n\n### System\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| `GET` | `/ojs/manifest` | Server manifest (version, capabilities) |\n| `GET` | `/ojs/v1/health` | Health check with Redis latency |\n\n### Jobs\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| `POST` | `/ojs/v1/jobs` | Enqueue a job |\n| `GET` | `/ojs/v1/jobs/{id}` | Get job details |\n| `DELETE` | `/ojs/v1/jobs/{id}` | Cancel a job |\n| `POST` | `/ojs/v1/jobs/batch` | Batch enqueue multiple jobs |\n\n### Workers\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| `POST` | `/ojs/v1/workers/fetch` | Fetch available jobs from queues |\n| `POST` | `/ojs/v1/workers/ack` | Acknowledge job completion |\n| `POST` | `/ojs/v1/workers/nack` | Report job failure |\n| `POST` | `/ojs/v1/workers/heartbeat` | Extend visibility timeout |\n\n### Queues\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| `GET` | `/ojs/v1/queues` | List all queues |\n| `GET` | `/ojs/v1/queues/{name}/stats` | Get queue statistics |\n| `POST` | `/ojs/v1/queues/{name}/pause` | Pause a queue |\n| `POST` | `/ojs/v1/queues/{name}/resume` | Resume a paused queue |\n\n### Dead Letter\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| `GET` | `/ojs/v1/dead-letter` | List dead letter jobs |\n| `POST` | `/ojs/v1/dead-letter/{id}/retry` | Retry a dead letter job |\n| `DELETE` | `/ojs/v1/dead-letter/{id}` | Delete a dead letter job |\n\n### Cron\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| `GET` | `/ojs/v1/cron` | List registered cron jobs |\n| `POST` | `/ojs/v1/cron` | Register a cron job |\n| `DELETE` | `/ojs/v1/cron/{name}` | Delete a cron job |\n\n### Workflows\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| `POST` | `/ojs/v1/workflows` | Create a workflow |\n| `GET` | `/ojs/v1/workflows/{id}` | Get workflow status |\n| `DELETE` | `/ojs/v1/workflows/{id}` | Cancel a workflow |\n\n## Configuration\n\nThe server is configured through environment variables:\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `OJS_PORT` | `8080` | HTTP server listen port |\n| `REDIS_URL` | `redis://localhost:6379` | Redis connection URL |\n\nThe `REDIS_URL` follows the standard Redis URI format: `redis://[user[:password]@]host[:port][/db]`\n\n## Project Structure\n\n```\nojs-backend-redis/\n├── cmd/\n│   └── ojs-server/\n│       └── main.go              # Application entry point\n├── internal/\n│   ├── api/                     # HTTP handlers and middleware\n│   │   ├── handler_jobs.go      # Job CRUD endpoints\n│   │   ├── handler_workers.go   # Worker fetch/ack/nack/heartbeat\n│   │   ├── handler_workflows.go # Workflow orchestration\n│   │   ├── handler_dead_letter.go\n│   │   ├── handler_batch.go\n│   │   ├── handler_queues.go\n│   │   ├── handler_cron.go\n│   │   ├── handler_system.go    # Health and manifest\n│   │   ├── middleware.go\n│   │   └── errors.go\n│   ├── core/                    # Domain models and interfaces\n│   │   ├── backend.go           # Backend interface definition\n│   │   ├── job.go               # Job and request structs\n│   │   ├── state.go             # Job state machine\n│   │   ├── validate.go          # Request validation\n│   │   ├── retry.go             # Retry policy configuration\n│   │   ├── unique.go            # Deduplication policy\n│   │   └── ...\n│   ├── redis/                   # Redis backend implementation\n│   │   ├── backend.go           # Core Redis operations\n│   │   ├── codec.go             # Job serialization\n│   │   └── keys.go              # Redis key schema\n│   ├── scheduler/               # Background processing loops\n│   │   └── scheduler.go\n│   └── server/                  # HTTP server setup\n│       ├── config.go            # Environment-based configuration\n│       └── server.go            # Router and route registration\n├── docker/\n│   ├── Dockerfile               # Multi-stage production build\n│   └── docker-compose.yml       # Redis + OJS server stack\n├── .github/workflows/\n│   ├── ci.yml                   # Build, lint, and test pipeline\n│   └── conformance.yml          # OJS conformance test suite\n├── Makefile\n├── go.mod\n└── go.sum\n```\n\n## Development\n\n### Makefile Targets\n\n| Target | Description |\n|--------|-------------|\n| `make build` | Compile the server binary |\n| `make run` | Build and run the server |\n| `make test` | Run tests with race detection and coverage |\n| `make lint` | Run static analysis (`go vet`) |\n| `make clean` | Remove build artifacts |\n| `make docker-up` | Start Redis + server via Docker Compose |\n| `make docker-down` | Stop Docker Compose services |\n| `make conformance` | Run all OJS conformance test levels |\n| `make conformance-level-N` | Run a specific conformance level (0–4) |\n\n### Running Tests\n\n```bash\nmake test\n```\n\n### Conformance Tests\n\nThe conformance test suite validates this implementation against the OJS specification. It requires the [ojs-conformance](https://github.com/openjobspec/ojs-conformance) repository checked out as a sibling directory:\n\n```bash\n# With the server running:\nmake conformance           # All levels\nmake conformance-level-0   # Individual level\n```\n\n## Contributing\n\nContributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup,\ntesting, and pull request expectations.\n\nPlease also review:\n\n- [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)\n- [SECURITY.md](SECURITY.md)\n- [CHANGELOG.md](CHANGELOG.md)\n\n## Observability\n\n### OpenTelemetry\n\nThe server supports distributed tracing via OpenTelemetry. Set the following environment variable to enable:\n\n```bash\nexport OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317\n```\n\nTraces are exported in OTLP format over gRPC. Compatible with Jaeger, Zipkin, Grafana Tempo, and any OTLP-compatible collector.\n\nYou can also use the legacy env vars `OJS_OTEL_ENABLED=true` and `OJS_OTEL_ENDPOINT` for explicit control.\n\n## Production Deployment Notes\n\n- **Rate limiting**: This server does not enforce request rate limits. Place a reverse proxy (e.g., Nginx, Envoy, or a cloud load balancer) in front of the server to add rate limiting in production.\n- **Authentication**: Set `OJS_API_KEY` to require Bearer token auth on all endpoints. For local-only testing, set `OJS_ALLOW_INSECURE_NO_AUTH=true`.\n- **TLS**: Terminate TLS at a reverse proxy or load balancer rather than at the application level.\n\n## License\n\nSee the [OpenJobSpec](https://github.com/openjobspec) organization for licensing details.\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenjobspec%2Fojs-backend-redis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenjobspec%2Fojs-backend-redis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenjobspec%2Fojs-backend-redis/lists"}