Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changepacks/changepack_log_l5MCZwGourHRr4xD6lAk4.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"changes":{"Cargo.toml":"Patch"},"note":"Impl cron","date":"2026-03-17T12:10:44.999667200Z"}
49 changes: 43 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 59 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,65 @@ let summary: vespera::schema::Schema = schema!(User, pick = ["id", "name"]);

---

## Cron Jobs

Schedule background tasks with `#[vespera::cron]`. Uses [tokio-cron-scheduler](https://crates.io/crates/tokio-cron-scheduler) under the hood.

### Enable Feature

```toml
[dependencies]
vespera = { version = "0.1", features = ["cron"] }
```

### Define Cron Jobs

Place `#[vespera::cron("...")]` on any `pub async fn` with zero parameters. The function can live anywhere in your project — no special directory required.

```rust
// src/cron/cleanup.rs, src/tasks.rs, or even src/routes/users.rs — anywhere works
#[vespera::cron("1/10 * * * * *")]
pub async fn cleanup_sessions() {
println!("Running cleanup every 10 seconds");
}

#[vespera::cron("0 0 * * * *")]
pub async fn hourly_report() {
println!("Running hourly report");
}
```

### How It Works

1. `#[cron("...")]` registers the job at compile time (like `#[route]`)
2. `vespera!()` auto-discovers all registered cron jobs — no extra parameters needed
3. A background scheduler spawns via `tokio::spawn` when the app starts

```rust
// No cron-specific config — just works
let app = vespera!(docs_url = "/docs");
```

### Cron Expression Format

Uses 6-field cron expressions (`sec min hour day month weekday`):

| Expression | Schedule |
|-----------|----------|
| `0 */5 * * * *` | Every 5 minutes |
| `0 0 * * * *` | Every hour |
| `0 0 0 * * *` | Daily at midnight |
| `1/10 * * * * *` | Every 10 seconds |
| `0 30 9 * * Mon-Fri` | Weekdays at 9:30 AM |

### Requirements

- Functions must be `pub async fn`
- Functions must take **no parameters** (no `State`, no extractors)
- The `cron` feature must be enabled

---

## Advanced Usage

### Adding State
Expand Down
3 changes: 3 additions & 0 deletions crates/vespera/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ repository.workspace = true

[features]
default = ["axum-extra/typed-header", "axum-extra/form", "axum-extra/query", "axum-extra/multipart", "axum-extra/cookie"]
cron = ["dep:tokio-cron-scheduler", "dep:tokio"]

[dependencies]
vespera_core = { workspace = true }
Expand All @@ -19,6 +20,8 @@ tempfile = "3"
serde_json = "1"
tower-layer = "0.3"
tower-service = "0.3"
tokio-cron-scheduler = { version = "0.13", optional = true }
tokio = { version = "1", features = ["rt"], optional = true }

[lints]
workspace = true
10 changes: 9 additions & 1 deletion crates/vespera/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub mod openapi {
pub use vespera_core::openapi::OpenApi;

// Re-export macros from vespera_macro
pub use vespera_macro::{Multipart, Schema, export_app, route, schema, schema_type, vespera};
pub use vespera_macro::{Multipart, Schema, cron, export_app, route, schema, schema_type, vespera};

// Re-export serde_json for merge feature (runtime spec merging)
pub use serde_json;
Expand All @@ -35,6 +35,14 @@ pub mod multipart;
// Re-export tempfile for schema_type! multipart mode (NamedTempFile)
pub use tempfile;

// Re-export tokio-cron-scheduler for cron job support
#[cfg(feature = "cron")]
pub use tokio_cron_scheduler;

// Re-export tokio for cron scheduler spawning
#[cfg(feature = "cron")]
pub use tokio;

// Re-export axum for convenience
pub mod axum {
pub use axum::*;
Expand Down
Loading