Firq — Multi-tenant Scheduler for Rust Services
Firq is an in-process scheduler for Rust backends that need stable tail latency under contention.
Key capabilities:
- Fair scheduling across tenants (DRR).
- Explicit backpressure and bounded memory behavior.
- Deadline-aware dequeue (
DropExpiredsemantics). - Metrics for queue saturation, drops, rejections, and queue-time percentiles.
firq-core is runtime-agnostic. firq-async adds Tokio support. firq-tower integrates with Tower/Axum.
Install
From crates.io
[]
= "0.1.2"
Tokio integration:
[]
= "0.1.2"
= "0.1.2"
Tower/Axum integration:
[]
= "0.1.2"
= "0.1.2"
= "0.1.2"
From source
Quick start
Stability / SemVer
- Firq is currently in
0.x; minor releases may include API-breaking changes. - Breaking changes include removing/renaming public types/functions, changing enum variants, or changing behavior in a way that requires code changes.
- Patch releases (
0.1.z) aim to be backward compatible and focus on fixes/hardening. - For production, pin a concrete release (
=0.1.2) or a conservative range (~0.1.2) and reviewCHANGELOG.mdbefore upgrades. - MSRV: Rust
1.85+(rust-version = "1.85"infirq-core,firq-async, andfirq-tower).
Getting started on docs.rs
firq-core: https://docs.rs/firq-core andcargo add firq-core@0.1.2firq-async: https://docs.rs/firq-async andcargo add firq-async@0.1.2firq-tower: https://docs.rs/firq-tower andcargo add firq-tower@0.1.2- Minimal, copyable examples are included in each crate-level
lib.rsdocs.
How to choose parameters
Use these as starting points, then tune with real traffic and stats() metrics.
shards: Start withmin(physical_cores, 8). Increase when many tenants are hot concurrently and enqueue lock contention is visible.max_globalandmax_per_tenant: Size from memory budget first. Approximate memory asmax_global * avg_task_size. Keepmax_per_tenantlow enough that one tenant cannot monopolize memory.quantumandcost: Treatcostas "work units" per task, andquantumas work units granted per round. If heavy jobs are starving, increasequantumor lower heavy-jobcostcalibration.deadlines: Use when stale work should be discarded (timeouts/SLO breaches). Expired items are removed lazily and should not permanently consume queue limits.- backpressure policy:
Rejectfor strict admission control,DropOldestPerTenant/DropNewestPerTenantfor lossy workloads,Timeoutwhen producers can wait briefly for capacity.
Queue limits are enforced against live pending work. Cancelled/expired entries are compacted lazily on dequeue and enqueue maintenance passes.
Core usage (firq-core)
Use this when workers are synchronous (threads) or when direct control over dequeue loops is required.
use ;
use HashMap;
use Instant;
let scheduler = new;
let tenant = from;
let task = Task ;
match scheduler.enqueue
match scheduler.dequeue_blocking
let stats = scheduler.stats;
println!;
Async usage (firq-async, Tokio)
Use this when producers/consumers are async and run under Tokio.
use ;
use Arc;
use Instant;
let core = new;
let scheduler = new;
let tenant = from;
let task = Task ;
match scheduler.enqueue
// Recommended for steady consumers: dedicated worker mode.
let mut receiver = scheduler.receiver_with_worker;
while let Some = receiver.recv.await
// Fallback for one-off dequeue calls:
let _ = scheduler.dequeue_async.await;
Axum usage (firq-tower)
firq-tower provides a Tower layer that handles scheduling, cancellation before turn, in-flight gating, and rejection mapping.
use ;
use ;
let firq_layer = new
.with_shards
.with_max_global
.with_max_per_tenant
.with_quantum
.with_in_flight_limit
.
.build;
let app = new
.route
.layer;
Default rejection mapping:
TenantFull->429GlobalFull->503Timeout->503
Actix-web usage (manual scheduling gate)
Firq does not currently provide a first-party firq-actix crate.
Use firq-async in handlers or middleware to gate work before executing heavy logic:
use ;
use ;
use Instant;
;
async
Runnable Actix example in this repository:
crates/firq-examples/src/bin/actix_web.rs
Benchmarks
Run reproducible scenarios:
Quick smoke run (same binary, full scenario set):
Scenarios in the benchmark binary include:
hot_tenant_sustainedburst_massivemixed_prioritiesdeadline_expirationcapacity_pressure
What to observe (without relying on fixed numbers):
- Fairness: in
hot_tenant_sustained, cold tenants should still be served. - Queue-time behavior: compare p95/p99 queue-time trends between schedulers.
- Backpressure/expiry signals: in
capacity_pressureanddeadline_expiration, verify drop/reject/expired counters respond as load changes.
Use runs to compare parameter sets and regressions; do not treat a single run as a universal baseline.
Repository layout
crates/firq-core: scheduler engine.crates/firq-async: Tokio adapter.crates/firq-tower: Tower layer.crates/firq-examples: runnable examples (publish = false).crates/firq-bench: benchmark runner (publish = false).
Community and governance
- Contribution guide:
CONTRIBUTING.md - Security policy:
SECURITY.md - Support channels:
SUPPORT.md - Release process:
RELEASING.md
Local quality gates
Release dry-runs:
# after firq-core is published on crates.io:
# after firq-async is published on crates.io:
License
This project is dual-licensed under:
- MIT (
LICENSE-MIT) - Apache-2.0 (
LICENSE-APACHE)