lifecycle-hooks
Adds post_construct and pre_destruct lifecycle hooks to injectable types. Use when initializing resources after construction (DB migrations, connection warm-up) or cleaning up before shutdown (pool cl
SKILL.mdskills/lifecycle-hooks/SKILL.md
GitHubLifecycle Hooks
Hook summary
| Hook | Runs | Common use |
|---|---|---|
#[injectable(post_construct)] |
After construction | Migrations, warm-up, cache load |
#[injectable(pre_destruct)] |
During container.shutdown() |
Close connections, flush, drain |
With constructor injection (same impl block)
use injectable::prelude::*;
#[injectable]
impl Database {
#[injectable(ctor)]
async fn new(#[injectable(inject(use_factory_async = make_pool))] pool: Pool<Sqlite>) -> Self {
Self { pool }
}
#[injectable(post_construct)]
async fn migrate(&self) -> Result<(), sqlx::Error> {
sqlx::query("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY)")
.execute(&self.pool).await?;
println!("[DB] Schema ready");
Ok(())
}
#[injectable(pre_destruct)]
async fn close(&self) {
self.pool.close().await;
println!("[DB] Pool closed");
}
}
With field injection (separate impl block)
#[injectable]
struct Cache { db: Inject<Database> }
#[injectable] // no #[injectable(ctor)] — lifecycle hooks only
impl Cache {
#[injectable(post_construct)]
async fn warm_up(&self) -> HookResult {
println!("[Cache] Warming up");
Ok(())
}
}
Hook return types
// Returns () — always succeeds
#[injectable(post_construct)]
fn init(&self) { println!("initialized"); }
// Returns Result — errors become LifecycleHookFailed
#[injectable(post_construct)]
async fn connect(&self) -> Result<(), std::io::Error> {
Ok(())
}
Shutdown
let container = Container::builder().build().await?;
// … use container …
container.shutdown().await?; // calls all #[injectable(pre_destruct)] hooks in reverse order
Hooks run in reverse construction order — the most-recently-constructed type is destroyed first.