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.1.0.tar.gz (63.4 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.1.0-py3-none-any.whl (17.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pulsar_scheduler-0.1.0.tar.gz
  • Upload date:
  • Size: 63.4 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.1.0.tar.gz
Algorithm Hash digest
SHA256 e9083f5ac6ff434f79d3330c1b3c33e0d4b61bc3990fb9f059c4ee6fda2df403
MD5 d7c796ee82a2e5db69a504c51ad38c45
BLAKE2b-256 c5a7db5104dac9af8608c4d497d9478ad2c4760c8113007e9407f7f470663113

See more details on using hashes here.

Provenance

The following attestation bundles were made for pulsar_scheduler-0.1.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.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pulsar_scheduler-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fa4f7890caaaa2d3d61c0a3e66758d736b03b001b202c79024fac18050d23923
MD5 97c58a62d5fdddd57e7bec5cb7ee3644
BLAKE2b-256 c6a84c36c2cc2879d328b21e84dd48f62cf9ce1c33d72bf099fcab09b1758da3

See more details on using hashes here.

Provenance

The following attestation bundles were made for pulsar_scheduler-0.1.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