1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111# HTTP API Implementation Plan for Petit Scheduler
## Overview
Add an HTTP API server that runs alongside the scheduler, enabling external CLI/tooling to trigger jobs and query status.
## API Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| `POST` | `/api/jobs/{job_id}/trigger` | Trigger a manual job run, returns `RunId` |
| `GET` | `/api/jobs` | List all registered jobs |
| `GET` | `/api/jobs/{job_id}` | Get job details |
| `GET` | `/api/jobs/{job_id}/runs` | List recent runs for a job (with `?limit=N`) |
| `GET` | `/api/runs/{run_id}` | Get run status and details |
| `GET` | `/api/runs/{run_id}/tasks` | Get task states for a run |
| `GET` | `/api/health` | Health check endpoint |
| `GET` | `/api/scheduler/state` | Get scheduler state (running/paused) |
| `POST` | `/api/scheduler/pause` | Pause scheduled triggers |
| `POST` | `/api/scheduler/resume` | Resume scheduled triggers |
## Implementation Steps
### 1. Add dependencies to Cargo.toml
- `axum` - HTTP framework (integrates well with existing tokio runtime)
- `tower-http` - Middleware (CORS, tracing)
### 2. Create API module structure
```
src/api/
โโโ mod.rs # Module exports, router construction
โโโ handlers.rs # Request handlers
โโโ responses.rs # JSON response types
โโโ errors.rs # Error type -> HTTP status mapping
```
### 3. Refactor storage to be shareable
Currently `Scheduler::new()` takes ownership of storage. Need to:
- Change to `Arc<S>` where `S: Storage`
- Pass same `Arc<S>` to both scheduler and API layer
**Files to modify:**
- `src/scheduler/engine.rs` - Change `storage: S` to `storage: Arc<S>`
- `src/main.rs` - Wrap storage in Arc before passing
### 4. Create shared application state
```rust
pub struct ApiState<S: Storage> {
pub handle: SchedulerHandle,
pub storage: Arc<S>,
pub jobs: Arc<HashMap<JobId, Job>>, // For job metadata lookup
}
```
### 5. Implement handlers
Map existing storage/handle methods to HTTP endpoints with proper error handling.
### 6. Add CLI flags for API server
- API server enabled by default
- `--no-api` flag to disable HTTP server
- `--api-port` to configure port (default: 8565)
- `--api-host` to configure bind address (default: 127.0.0.1)
### 7. Update main.rs to spawn API server
Run HTTP server as separate tokio task alongside scheduler.
## Error Mapping
| Error | HTTP Status |
|-------|-------------|
| `JobNotFound` | 404 |
| `StorageError::NotFound` | 404 |
| `DependencyNotSatisfied` | 409 Conflict |
| `MaxConcurrentRunsExceeded` | 429 Too Many Requests |
| `NotRunning` | 503 Service Unavailable |
| Other | 500 Internal Server Error |
## Files to Create/Modify
| File | Action |
|------|--------|
| `src/api/mod.rs` | Create |
| `src/api/handlers.rs` | Create |
| `src/api/responses.rs` | Create |
| `src/api/errors.rs` | Create |
| `src/lib.rs` | Add `pub mod api;` |
| `src/main.rs` | Add CLI flags, spawn API server |
| `src/scheduler/engine.rs` | Refactor to use `Arc<S>` |
| `Cargo.toml` | Add axum, tower-http |
## Example Usage
```bash
# Start scheduler (API enabled by default on port 8565)
petit --db petit.db run examples/jobs
# Start without API
petit --db petit.db run examples/jobs --no-api
# Custom port
petit --db petit.db run examples/jobs --api-port 9000
# Trigger job from another terminal
curl -X POST http://localhost:8565/api/jobs/hello_world/trigger
# Check run status
curl http://localhost:8565/api/runs/<run-id>
# List jobs
curl http://localhost:8565/api/jobs
```