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
.duckdbfile - 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
crashedon 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.executableto 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
runningare set tocrashed. - The DuckDB file is portable — just copy
Pulsar.duckdbto move your setup.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e9083f5ac6ff434f79d3330c1b3c33e0d4b61bc3990fb9f059c4ee6fda2df403
|
|
| MD5 |
d7c796ee82a2e5db69a504c51ad38c45
|
|
| BLAKE2b-256 |
c5a7db5104dac9af8608c4d497d9478ad2c4760c8113007e9407f7f470663113
|
Provenance
The following attestation bundles were made for pulsar_scheduler-0.1.0.tar.gz:
Publisher:
python-publish.yml on mz-jy/pulsar
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pulsar_scheduler-0.1.0.tar.gz -
Subject digest:
e9083f5ac6ff434f79d3330c1b3c33e0d4b61bc3990fb9f059c4ee6fda2df403 - Sigstore transparency entry: 1525354050
- Sigstore integration time:
-
Permalink:
mz-jy/pulsar@acf0000675a9de223d62680b7f9c41a3c5ee1984 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/mz-jy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@acf0000675a9de223d62680b7f9c41a3c5ee1984 -
Trigger Event:
release
-
Statement type:
File details
Details for the file pulsar_scheduler-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pulsar_scheduler-0.1.0-py3-none-any.whl
- Upload date:
- Size: 17.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa4f7890caaaa2d3d61c0a3e66758d736b03b001b202c79024fac18050d23923
|
|
| MD5 |
97c58a62d5fdddd57e7bec5cb7ee3644
|
|
| BLAKE2b-256 |
c6a84c36c2cc2879d328b21e84dd48f62cf9ce1c33d72bf099fcab09b1758da3
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pulsar_scheduler-0.1.0-py3-none-any.whl -
Subject digest:
fa4f7890caaaa2d3d61c0a3e66758d736b03b001b202c79024fac18050d23923 - Sigstore transparency entry: 1525354061
- Sigstore integration time:
-
Permalink:
mz-jy/pulsar@acf0000675a9de223d62680b7f9c41a3c5ee1984 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/mz-jy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@acf0000675a9de223d62680b7f9c41a3c5ee1984 -
Trigger Event:
release
-
Statement type: