{"id":51195924,"url":"https://github.com/z4jdev/z4j-scheduler","last_synced_at":"2026-06-27T20:31:18.216Z","repository":{"id":361049199,"uuid":"1228455171","full_name":"z4jdev/z4j-scheduler","owner":"z4jdev","description":"Engine-agnostic dynamic scheduler for the z4j stack (Apache 2.0)","archived":false,"fork":false,"pushed_at":"2026-06-08T05:21:50.000Z","size":351,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-08T07:18:41.161Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://pypi.org/project/z4j-scheduler/","language":"Python","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/z4jdev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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-05-04T03:14:19.000Z","updated_at":"2026-06-08T05:21:53.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/z4jdev/z4j-scheduler","commit_stats":null,"previous_names":["z4jdev/z4j-scheduler"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/z4jdev/z4j-scheduler","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/z4jdev%2Fz4j-scheduler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/z4jdev%2Fz4j-scheduler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/z4jdev%2Fz4j-scheduler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/z4jdev%2Fz4j-scheduler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/z4jdev","download_url":"https://codeload.github.com/z4jdev/z4j-scheduler/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/z4jdev%2Fz4j-scheduler/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34867616,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-27T02:00:06.362Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2026-06-27T20:31:16.437Z","updated_at":"2026-06-27T20:31:18.200Z","avatar_url":"https://github.com/z4jdev.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# z4j-scheduler\n\n[![PyPI version](https://img.shields.io/pypi/v/z4j-scheduler.svg?v=1.6.7)](https://pypi.org/project/z4j-scheduler/)\n[![Python](https://img.shields.io/pypi/pyversions/z4j-scheduler.svg?v=1.6.7)](https://pypi.org/project/z4j-scheduler/)\n[![License](https://img.shields.io/pypi/l/z4j-scheduler.svg?v=1.6.7)](https://github.com/z4jdev/z4j-scheduler/blob/main/LICENSE)\n\nThe engine-agnostic dynamic scheduler for [z4j](https://z4j.com).\n\nOne service drives Celery, RQ, Dramatiq, Huey, arq, and TaskIQ from\na single dashboard. Schedules live in z4j's database, you edit\nthem live without restarting anything, every change is recorded in\nan HMAC-chained audit log, and importers + exporters keep the door\nopen in either direction. This is the canonical scheduler when you\nwant one place to manage cron / interval / one-shot / solar\nschedules across mixed engines.\n\n## Compatibility\n\nPython 3.11+. PostgreSQL 17+ for shared-database HA (SQLite supported for single-node deployments). Fans out to whichever engines you install on the same host (Celery, RQ, Dramatiq, Huey, arq, TaskIQ); each engine extra carries its own upstream version floor.\n\nFull per-adapter matrix at \u003chttps://z4j.dev/reference/compatibility/\u003e.\n\n## What makes z4j-scheduler different\n\nz4j-scheduler is a deliberate alternative to in-language schedulers\nlike celery-beat, rq-scheduler, and APScheduler. The differences\nthat matter day to day:\n\n- **Engine-agnostic.** One scheduler service for every supported\n  Python task engine. A project running Celery for legacy services\n  and arq for a FastAPI rewrite uses the same scheduler for both,\n  with one dashboard and one audit trail.\n- **Live editing.** Schedules live in z4j's Postgres database.\n  Create, edit, pause, resume, rename, and delete from the dashboard\n  or REST API without a daemon restart. celery-beat needs a\n  beat-process restart for static-config edits, rq-scheduler stores\n  schedules in Redis but has no editing UI, APScheduler edits are\n  in-process.\n- **HMAC-chained audit log.** Every schedule mutation (who, what,\n  when, from which IP) is recorded in a tamper-evident audit chain\n  alongside the brain's other audit rows. celery-beat keeps no\n  record. django-celery-beat keeps a partial record only if you\n  wired up django-auditlog.\n- **HA-ready.** Multiple scheduler instances can run against the\n  same Postgres database. Postgres advisory locks elect one leader\n  to tick; followers stay warm. Rolling restarts and leader\n  failovers are seconds, not minutes, with no missed-fire window\n  beyond the per-schedule catch-up policy.\n- **Reversible by design.** Importers cover celery-beat (static and\n  django-celery-beat), rq-scheduler, APScheduler jobstores, Huey\n  `@periodic_task`, arq cron, taskiq schedule sources, and system\n  crontab. Exporters write any schedule back to those same formats.\n  Round-trip integrity is pinned by tests so you can leave whenever\n  you want; the schedule definitions are yours, not ours.\n\n## What it ships\n\n| Capability | Notes |\n|---|---|\n| Schedule kinds | cron, interval, one-shot, solar (sunrise / sunset / dawn / dusk / noon / midnight at a given lat / lon) |\n| Live editing | dashboard, REST API, declarative config; no restart required |\n| Engine fan-out | Celery, RQ, Dramatiq, Huey, arq, TaskIQ |\n| Importers | celery / django-celery-beat / rq-scheduler / apscheduler / huey-periodic / arq-cron / taskiq-scheduler / cron |\n| Exporters | every native format above; round-trip integrity tested |\n| HA leader election | Postgres advisory lock, followers stay warm |\n| Audit log | every mutation HMAC-chained, tamper-evident |\n| Catch-up policy | per-schedule: skip, fire one missed, fire all missed |\n| Timezones | IANA zones validated at the boundary; DST fall-back fold fixed (no double-fires); spring-forward gap handled |\n| Trigger surface | brain dispatches `trigger_now` over a private gRPC channel so the scheduler's last-fire cache stays consistent |\n\n## Install\n\nStandalone (recommended for production):\n\n```bash\npip install z4j-scheduler\nz4j-scheduler serve\n```\n\nEmbedded inside z4j (recommended for homelab and small teams):\n\n```bash\npip install 'z4j[scheduler-embedded]'\n# enable in brain settings: Z4J_EMBEDDED_SCHEDULER=true\n```\n\nMigrate existing schedules in:\n\n```bash\npip install 'z4j-scheduler[celery-import]'\nz4j-scheduler import \\\n  --from celery \\\n  --celery-app myapp.celery:app \\\n  --project myproject \\\n  --brain-url https://brain.example.com \\\n  --api-token \"$Z4J_SCHEDULER_BRAIN_API_TOKEN\"\n```\n\nThe other importer subcommands follow the same shape (`--from rq`,\n`--from apscheduler`, `--from django-celery-beat`, etc.). All run in\n`--dry-run` mode by default; you review the diff before any write.\n\n## When to choose z4j-scheduler\n\nYou probably want it if:\n\n- You run more than one Python task engine and want one schedule\n  surface across all of them.\n- An auditor or a security review asks who paused the nightly\n  billing job last Tuesday and you don't have a clean answer.\n- You're tired of restarting celery-beat to change a cron expression.\n- You want HA scheduling without standing up a second control\n  plane.\n- You're considering a one-time migration from celery-beat /\n  rq-scheduler / APScheduler and want a reversible path.\n\nYou probably don't need it if:\n\n- You run a single engine (typically Celery), have no compliance\n  pressure, and the in-language scheduler already meets your needs.\n  Stay where you are; we ship z4j-celerybeat / z4j-rqscheduler /\n  z4j-apscheduler as observation-only adapters that surface those\n  schedules in the z4j dashboard without taking ownership.\n\n## Documentation\n\nFull docs at [z4j.dev/scheduler/](https://z4j.dev/scheduler/).\nThe migration guide at\n[z4j.dev/scheduler/migrating-from-celery-beat/](https://z4j.dev/scheduler/migrating-from-celery-beat/)\nwalks the importer + dashboard verification path step by step.\n\n## License\n\nApache-2.0, see [LICENSE](LICENSE). Importing z4j-scheduler does\nnot affect your application's licensing. z4j (server +\ndashboard + API) is AGPL v3, isolated in its own process; the\nscheduler is separate.\n\n## Links\n\n- Homepage: https://z4j.com\n- Documentation: https://z4j.dev\n- PyPI: https://pypi.org/project/z4j-scheduler/\n- Issues: https://github.com/z4jdev/z4j-scheduler/issues\n- Changelog: [CHANGELOG.md](CHANGELOG.md)\n- Security: security@z4j.com (see [SECURITY.md](SECURITY.md))\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fz4jdev%2Fz4j-scheduler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fz4jdev%2Fz4j-scheduler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fz4jdev%2Fz4j-scheduler/lists"}