diff --git a/AGENTS.md b/AGENTS.md index fc9dd6f..3520f61 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,13 +6,13 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co `modern-di-taskiq` is a taskiq integration for [`modern-di`](https://github.com/modern-python/modern-di); [`CONTEXT.md`](CONTEXT.md) opens with -what it does and owns the vocabulary — read it before naming a concept in code, a test name, or an +what it does and owns the vocabulary. Read it before naming a concept in code, a test name, or an issue title. It is one of that project's integrations, each of which lives in a separate repository and ships as a separate PyPI package. ## Commands -`just` (task runner) and `uv` (package manager). The [`justfile`](justfile) is the source of truth — +`just` (task runner) and `uv` (package manager). The [`justfile`](justfile) is the source of truth: `just --list`, or read it. ## Architecture diff --git a/CONTEXT.md b/CONTEXT.md index 6759955..43ae9d3 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -11,8 +11,8 @@ A term is listed only when there is a synonym to reject, or a meaning subtle eno docs must agree on it. General programming vocabulary does not belong here, however heavily this package uses it. -The domain terms are `modern-di`'s — `Container`, `Provider`, `Group`, `Scope`, `Resolution`, -`Override` — and taskiq's — broker, worker, task, message, middleware, result backend. Those +The domain terms are `modern-di`'s (`Container`, `Provider`, `Group`, `Scope`, `Resolution`, +`Override`) and taskiq's (broker, worker, task, message, middleware, result backend). Those projects are the authority for all of them; nothing here redefines one. The two below are this package's own. @@ -21,12 +21,12 @@ The `Container` that `setup_di` attaches to `broker.state`: the one a caller con in, and the one `fetch_di_container` returns. By default the worker's startup event opens it, and shutdown closes it after all `WORKER_SHUTDOWN` handlers and middleware `shutdown()` calls; with `setup_di(..., manage_lifespan=False)` the caller does. -_Avoid_: APP-scope container — that names a scope where what matters is the position at the top of +_Avoid_: APP-scope container. That names a scope where what matters is the position at the top of the tree, and `Scope.APP` is `modern-di`'s word for a band in the hierarchy, not for this object. **Per-task child**: The child container built for one task execution, carrying that task's `TaskiqMessage` as context. Exactly one exists per task: every `FromDI` parameter in a task shares it, no two tasks share one, -and it is closed when the task ends — including when the task raises. -_Avoid_: request child — `REQUEST` is the scope it sits at, but nothing here is a request; the unit +and it is closed when the task ends, including when the task raises. +_Avoid_: request child. `REQUEST` is the scope it sits at, but nothing here is a request; the unit of work is a task. diff --git a/docs/adr/0002-only-worker-lifecycle-is-wired.md b/docs/adr/0002-only-worker-lifecycle-is-wired.md index 87df7e3..bc96999 100644 --- a/docs/adr/0002-only-worker-lifecycle-is-wired.md +++ b/docs/adr/0002-only-worker-lifecycle-is-wired.md @@ -5,7 +5,7 @@ kicker constructs the broker and calls `.kiq()` without ever running a task, so a container opened on `CLIENT_STARTUP` would hold app-scoped connections and pools for a process that resolves nothing from them, then close them on a shutdown event a short-lived script often never fires. The cost is -documented in `README.md` rather than hidden: a process that both kicks and executes gets no +documented in `README.md`: a process that both kicks and executes gets no lifecycle unless the worker events fire, which `InMemoryBroker.startup()` arranges by firing both pairs. `container.open()` on worker startup is unconditional and a no-op on a fresh container; it earns its keep on a second worker cycle, reopening what the previous `WORKER_SHUTDOWN` closed. From