Agents/Concurrency & state
curfew
The Timekeeper
Runs work in parallel and keeps only what finishes before the deadline.
Downloads per day
Last 90 days · 9 total · peak 8
Dossier
What curfew does.
Spawns tasks across threads, joins at an absolute deadline, and collects only the results that arrived in time.
From the crate: “A deadline-aware fork-join model where multiple tasks run in parallel, but only those that finish before a specified absolute clock time are joined and their results collected.”
- Codename
- The Timekeeper
- Role
- Deadline fork-join
- Character
- Strict about time and unsentimental about stragglers. When the clock strikes, it leaves without them.
- Domain
- Concurrency & state
- Enlisted
- 8 October 2026
- Last release
- v0.0.5, 8 October 2026
- Keywords
concurrency,deadline,fork-join,real-time
Use cases
Put it to work.
- Gather quotes or results from several sources and answer on time with whatever arrived.
- Keep the real-time part of a program moving when some workers are slow.
- Use the optional Tokio feature for async tasks.
Getting started
Call it in.
Add it to a Rust project, then follow the example. The full API is on docs.rs.
Install
cargo add curfew
Example
use curfew::{DeadlineJoiner, TaskOutcome};
use std::thread;
use std::time::{Duration, Instant};
fn main() {
let deadline = Instant::now() + Duration::from_millis(200);
let mut joiner = DeadlineJoiner::new(deadline);
for job in 0..4 {
joiner.spawn(move || {
// staggered work with different run times
thread::sleep(Duration::from_millis(40 * job));
job * 10
});
}
let summary = joiner.join_ready();
println!("completed before deadline: {}", summary.completed_count());
println!("missed deadline: {}", summary.timed_out_count());
for task in summary.completed {
match task.outcome {
TaskOutcome::Completed(value) => println!("task {} => {value}", task.task_id),
TaskOutcome::Panicked(info) => println!("task {} panicked: {}", task.task_id, info),
}
}
}More
use curfew::{join_with_deadline, JoinOutcome, TaskOutcome};
use std::thread;
use std::time::{Duration, Instant};
fn main() {
let handle = thread::spawn(|| {
thread::sleep(Duration::from_millis(150));
99
});
match join_with_deadline(handle, Instant::now() + Duration::from_millis(80)) {
JoinOutcome::Completed(result) => match result.outcome {
TaskOutcome::Completed(value) => println!("finished on time: {value}"),
TaskOutcome::Panicked(info) => println!("task panicked: {info}"),
},
JoinOutcome::TimedOut(late) => {
println!("missed deadline; waiting asynchronously for the late result");
let result = late.wait();
println!("late completion: {:?}", result.outcome);
}
}
}More
use curfew::{
join_with_deadline_async, DeadlineJoinerAsync, JoinOutcomeAsync, TaskOutcome,
};
use std::time::{Duration, Instant};
#[tokio::main(flavor = "current_thread")]
async fn main() {
let deadline = Instant::now() + Duration::from_millis(120);
let mut joiner = DeadlineJoinerAsync::new(deadline);
for value in 0..3u32 {
joiner.spawn(async move {
tokio::time::sleep(Duration::from_millis(u64::from(30 * (value + 1))))
.await;
value
});
}
let summary = joiner.join_ready().await;
println!("async tasks finished on time: {}", summary.completed_count());
let future = async {
tokio::time::sleep(Duration::from_millis(200)).await;
99
};
match join_with_deadline_async(future, Instant::now() + Duration::from_millis(60)).await {
JoinOutcomeAsync::Completed(result) => match result.outcome {
TaskOutcome::Completed(value) => println!("completed on time: {value}"),
TaskOutcome::Panicked(info) => println!("task panicked: {info}"),
},
JoinOutcomeAsync::TimedOut(late) => {
println!("future missed the deadline; waiting for late completion");
let result = late.wait().await;
println!("late outcome: {:?}", result.outcome);
}
}
}Build with a prompt
Add the Rust crate `curfew` (version 0.0.5) to this project with `cargo add curfew`. I want to use it for this: Spawns tasks across threads, joins at an absolute deadline, and collects only the results that arrived in time. Before writing code, read its README at https://crates.io/crates/curfew and the API docs at https://docs.rs/curfew. Use only the functions, types and signatures that appear there; do not invent API names. Write a minimal working example and one test that runs it.
Paste this into Claude Code or another coding agent.
Specs
- Version
- 0.0.5 (pre-0.1, API may change)
- License
- MIT
- Edition
- Rust 2021
- Size
- 439 lines of code, 1 of comments
- Package
- 12.3 KB compressed
- Dependencies
- crossbeam-channel, futures, log, tokio
- Used by
- 0 crates on crates.io
- Features
- tokio
- Docs
- docs.rs, built
- Repository
- cryptopatrick/curfew · 0★ · 0 forks · 0 open issues · pushed 17 Oct 2025
Release history
| Version | Date | Downloads |
|---|---|---|
| 0.0.5 | 8 Oct 2026 | 9 |
Documentation
The manual.
The crate's README as published on crates.io. The full API reference is on docs.rs.
Read the README
curfew
curfew is a deadline-aware fork-join helper for Rust. It lets you spin up work across
multiple threads, set an absolute deadline (std::time::Instant), and collect only the
results that arrive on time. Late workers are skipped without attempting to cancel them,
so real-time sections of your application can keep moving.
Installation
Add the crate to your Cargo manifest:
[dependencies]
curfew = "0.0.5"
Enable the optional tokio feature to work with async tasks powered by Tokio.
Usage
Joining a group of tasks before a deadline
use curfew::{DeadlineJoiner, TaskOutcome};
use std::thread;
use std::time::{Duration, Instant};
fn main() {
let deadline = Instant::now() + Duration::from_millis(200);
let mut joiner = DeadlineJoiner::new(deadline);
for job in 0..4 {
joiner.spawn(move || {
// staggered work with different run times
thread::sleep(Duration::from_millis(40 * job));
job * 10
});
}
let summary = joiner.join_ready();
println!("completed before deadline: {}", summary.completed_count());
println!("missed deadline: {}", summary.timed_out_count());
for task in summary.completed {
match task.outcome {
TaskOutcome::Completed(value) => println!("task {} => {value}", task.task_id),
TaskOutcome::Panicked(info) => println!("task {} panicked: {}", task.task_id, info),
}
}
}
Joining an individual handle with a deadline
use curfew::{join_with_deadline, JoinOutcome, TaskOutcome};
use std::thread;
use std::time::{Duration, Instant};
fn main() {
let handle = thread::spawn(|| {
thread::sleep(Duration::from_millis(150));
99
});
match join_with_deadline(handle, Instant::now() + Duration::from_millis(80)) {
JoinOutcome::Completed(result) => match result.outcome {
TaskOutcome::Completed(value) => println!("finished on time: {value}"),
TaskOutcome::Panicked(info) => println!("task panicked: {info}"),
},
JoinOutcome::TimedOut(late) => {
println!("missed deadline; waiting asynchronously for the late result");
let result = late.wait();
println!("late completion: {:?}", result.outcome);
}
}
}
Async tasks with Tokio (tokio feature)
use curfew::{
join_with_deadline_async, DeadlineJoinerAsync, JoinOutcomeAsync, TaskOutcome,
};
use std::time::{Duration, Instant};
#[tokio::main(flavor = "current_thread")]
async fn main() {
let deadline = Instant::now() + Duration::from_millis(120);
let mut joiner = DeadlineJoinerAsync::new(deadline);
for value in 0..3u32 {
joiner.spawn(async move {
tokio::time::sleep(Duration::from_millis(u64::from(30 * (value + 1))))
.await;
value
});
}
let summary = joiner.join_ready().await;
println!("async tasks finished on time: {}", summary.completed_count());
let future = async {
tokio::time::sleep(Duration::from_millis(200)).await;
99
};
match join_with_deadline_async(future, Instant::now() + Duration::from_millis(60)).await {
JoinOutcomeAsync::Completed(result) => match result.outcome {
TaskOutcome::Completed(value) => println!("completed on time: {value}"),
TaskOutcome::Panicked(info) => println!("task panicked: {info}"),
},
JoinOutcomeAsync::TimedOut(late) => {
println!("future missed the deadline; waiting for late completion");
let result = late.wait().await;
println!("late outcome: {:?}", result.outcome);
}
}
}
API Highlights
DeadlineJoinerspawns tasks, tracks their start/finish instants, and only returns results that beat the deadline.join_with_deadlinewraps a singleJoinHandle, returning aLateTaskso callers can optionally await the late result later.- Enable the
tokiofeature for async siblingsDeadlineJoinerAsyncandjoin_with_deadline_asyncwith the same semantics. - Rich metadata via
TaskResult,TaskOutcome, andTimedOutTaskfor diagnostics and logging.
Limitations
- Tasks are never forcefully terminated. Anything that misses the deadline continues running in the background until it completes naturally.
- Deadlines rely on the monotonic
Instantclock. System clock adjustments do not influence scheduling, but very long sleeps may still drift.
Examples
Run the bundled examples with cargo run --example basic or see examples/ for more
scenarios (enable --features tokio for async_example).
Development
See _dev/PRD.md for the full product specification and CONTRIBUTING.md for contribution guidelines.
License
This project is licensed under MIT. See LICENSE for details.
Resources
Same unit