Run background work
Use this when: work must happen on its own—periodic cleanup, imports, or reconciliation—without a browser or API request triggering it.
The framework supervises workers. It is not a durable job queue: job storage, delivery guarantees, retries, and scheduling policy remain application decisions. This guide shows the lifecycle wiring around one operation.
1. Add the dependencies
Create examples/my-worker/Cargo.toml:
[package]
name = "my-worker"
version = "0.1.0"
edition = "2024"
publish = false
[workspace]
[dependencies]
iet-app = { path = "../../crates/core/iet-app" }
iet-config = { path = "../../crates/core/iet-config" }
iet-config-env = { path = "../../crates/features/iet-config-env" }
iet-core = { path = "../../crates/core/iet-core" }
iet-runtime-tokio = { path = "../../crates/features/iet-runtime-tokio" }
tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal", "time"] }
iet-app defines the worker and shutdown contracts. iet-runtime-tokio runs and
drains them. iet-core supplies AppResult/AppError; it does not start a server.
2. Write the worker
This complete program runs one placeholder operation every five seconds, then
exits cleanly on Ctrl+C. Replace expire_tasks_once with your real operation.
use Duration;
use ;
use ConfigSource;
use AppResult;
use TokioRuntime;
;
async
async
3. Run it
checking for expired tasks
It repeats every five seconds. Stop it with Ctrl+C. The operation's AppError
propagates out of run, so the process does not silently continue after a failure.
One operation, several callers
expire_tasks_once can call the same service used by your page or HTTP handler.
The worker supplies the trigger and lifecycle; it should not duplicate the
business rule. This example is public and uses no database, so a real operation
will add configuration, a session, and authorization as needed.
What the runtime guarantees
The framework handles
- Starting each injected module's worker.
- Reporting a worker failure and stopping the application.
- Signalling shutdown and waiting up to the configured drain time.
- Aborting remaining tasks if the drain deadline expires.
Your application handles
- What each operation does and when it should run.
- Job persistence, duplicate delivery, retries, and backoff.
- Database sessions, transactions, and ownership checks.
- Idempotency when an operation may run more than once.
If a worker returns Ok(()) unexpectedly, the runtime treats that as an
unavailable worker rather than successful application completion. A deliberate
one-shot process is a command, not a long-running worker.
Add another worker
inject accepts another Module with a unique name:
// Fragment: each module prepares and starts independently.
let app = new
.configuration
.runtime
.inject
.inject;
Starting and draining are supervised together. There is no built-in cross-worker ordering guarantee, so do not rely on one finishing before another starts unless you coordinate that explicitly.
Source: crates/core/iet-app/src/lib.rs and
crates/features/iet-runtime-tokio/src/lib.rs.