Skip to main content

Lightweight Python job scheduler with cron, DuckDB, web UI, and CLI

Project description

⚡ Pulsar

A lightweight Python process manager with DuckDB persistence, cron scheduling, a web UI, and a CLI.

Features

  • Cron scheduling — register Python scripts with standard 5-field cron expressions
  • DuckDB storage — all jobs and run history persisted in a single .duckdb file
  • Web UI — real-time dashboard at http://localhost:8844 (auto-refreshes every 5s)
  • REST API — full CRUD on jobs and runs at /api/* (Swagger docs at /docs)
  • CLI — add, list, trigger, remove jobs and view history from the terminal
  • Manual triggers — run any job on-demand from the UI or CLI
  • Log capture — stdout/stderr captured per run and viewable in the UI
  • Process tracking — PIDs tracked, stale runs marked as crashed on restart

Quick Start

# 1. Install
pip install pulsar-scheduler

# 2. Start the server
pulsar serve

# 3. Open http://localhost:8844 in your browser

Project Structure

Pulsar/
├── main.py           # Entry point — CLI + server bootstrap
├── db.py             # DuckDB schema & thread-safe queries
├── executor.py       # Subprocess execution in background threads
├── scheduler.py      # APScheduler cron wrapper
├── server.py         # FastAPI app + embedded HTML UI
├── requirements.txt
├── example_job.py    # Sample job (succeeds)
└── example_fail.py   # Sample job (fails — for testing)

CLI Usage

Start the server

python main.py serve [--host 0.0.0.0] [--port 8844] [--db Pulsar.duckdb]

Register a job

# Run example_job.py every 5 minutes
python main.py add my-job ./example_job.py "*/5 * * * *"

# With extra arguments
python main.py add etl-daily ./etl.py "0 2 * * *" --args "--env prod --verbose"

List jobs

python main.py list

Trigger a job manually

python main.py trigger <job_id>

Remove a job

python main.py remove <job_id>

View run history

python main.py history
python main.py history --job-id <id> --limit 10

REST API

Method Endpoint Description
GET /api/status Server status & uptime
GET /api/jobs List all jobs
POST /api/jobs Register a new job
DELETE /api/jobs/{id} Remove a job
POST /api/jobs/{id}/trigger Trigger a job manually
POST /api/jobs/{id}/toggle Enable/disable a job
GET /api/runs?job_id=&limit=50 List runs
POST /api/runs/{id}/cancel Cancel a running job
POST /api/reload Reload jobs from DB

Example: add a job via API

curl -X POST http://localhost:8844/api/jobs \
  -H "Content-Type: application/json" \
  -d '{"name":"my-job","script_path":"./example_job.py","cron_expression":"*/5 * * * *"}'

Cron Syntax

Standard 5-field cron expressions:

┌───────────── minute (0–59)
│ ┌───────────── hour (0–23)
│ │ ┌───────────── day of month (1–31)
│ │ │ ┌───────────── month (1–12)
│ │ │ │ ┌───────────── day of week (0–6, Mon=1)
│ │ │ │ │
* * * * *
Expression Meaning
*/5 * * * * Every 5 minutes
0 9 * * * Daily at 09:00
0 */2 * * * Every 2 hours
0 9 * * 1 Every Monday at 09:00
30 8 1 * * 1st of every month at 08:30

Architecture

                ┌──────────┐
  CLI ─────────►│          │
                │  DuckDB  │◄──── state persistence
  Web UI ──────►│          │
                └────┬─────┘
                     │
              ┌──────┴──────┐
              │   FastAPI    │◄──── REST API + HTML
              │   Server     │
              └──────┬──────┘
                     │
              ┌──────┴──────┐
              │ APScheduler  │◄──── cron triggers
              └──────┬──────┘
                     │
              ┌──────┴──────┐
              │  Executor    │◄──── subprocess.Popen per job
              │  (threads)   │
              └─────────────┘

Notes

  • The server uses sys.executable to run scripts, so jobs use the same Python interpreter.
  • Stdout/stderr are captured after the process finishes (not streamed).
  • Logs are truncated to 50 KB per run to keep the database lean.
  • On server restart, any runs still marked as running are set to crashed.
  • The DuckDB file is portable — just copy Pulsar.duckdb to move your setup.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pulsar_scheduler-0.2.0.tar.gz (65.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pulsar_scheduler-0.2.0-py3-none-any.whl (20.1 kB view details)

Uploaded Python 3

File details

Details for the file pulsar_scheduler-0.2.0.tar.gz.

File metadata

  • Download URL: pulsar_scheduler-0.2.0.tar.gz
  • Upload date:
  • Size: 65.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pulsar_scheduler-0.2.0.tar.gz
Algorithm Hash digest
SHA256 026a7b3206c1e39bba0663d24dc744f36cf3518e6f4105066890b79e82537c2c
MD5 62893617b8bc3ab7207b03858bb46188
BLAKE2b-256 0f16f38ebdbdd4a7a72de04213cfe4d67f1c7b3174cc1ad79abbfa64667c92c2

See more details on using hashes here.

Provenance

The following attestation bundles were made for pulsar_scheduler-0.2.0.tar.gz:

Publisher: python-publish.yml on mz-jy/pulsar

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pulsar_scheduler-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pulsar_scheduler-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 09efdde85979af4c3385a8aa817e8d3b402d5e0e35d006883147a106c230abb0
MD5 62c3405652eb91b3beca86412f10cf54
BLAKE2b-256 70234323f4a1802cd69440e81ef0bdfe4e9a92dbe9dc6776178e856d4d4750dd

See more details on using hashes here.

Provenance

The following attestation bundles were made for pulsar_scheduler-0.2.0-py3-none-any.whl:

Publisher: python-publish.yml on mz-jy/pulsar

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page