Document Celery subinterpreter task seams (#66) - #99
Conversation
SummaryThis pull request resolves issue Key changesDocumentation
Core implementation
Testing
Related artefacts
VerificationAll checks passed: WalkthroughReconcile the Celery worker scaffold with Python 3.14 subinterpreter concurrency by establishing a metrics foundation, hardening executor lifecycle with locked state and injection points, documenting the task-level integration seam, and validating the pattern with comprehensive tests covering ordering, lifecycle races, observability and eager Celery invocation. ChangesCelery–subinterpreter concurrency reconciliation
Possibly related PRs
📋 Issue PlannerBuilt with CodeRabbit's Coding Plans for faster development and fewer bugs. View plan used: ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
|
Reviewer's GuideDocuments and clarifies the boundary between Celery worker runtime configuration and the Python 3.14 interpreter-pool executor, and cross-links ADR/docs so CPU-bound task authors can discover and use the interpreter-pool fan-out path correctly. File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
@coderabbitai Please investigate the cause of the following issue using codegraph exploration and research, identify a fix and provide an AI coding agent prompt for the fix: |
This comment was marked as resolved.
This comment was marked as resolved.
|
@coderabbitai what?! You're not supposed to be telling the developer how to bypass the lint |
This comment was marked as resolved.
This comment was marked as resolved.
8293b25 to
4d9fd0e
Compare
Add eager Celery task-body coverage for the interpreter-pool executor pattern so the documented integration point is exercised through the worker runtime boundary. Add Hypothesis properties for `map_ordered()` ordering across inline and interpreter-backed executors, and record that PR `#99` closed the Celery integration gap from issue `#66`.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@coderabbitai Have the following failed checks now been resolved? If further work is required, please provide an AI agent prompt for the remaining work to be done to address these failures. Do not treat warnings as optional or aspirational. Where a change is out of scope for this PR, propose a GitHub issue unless one exists already. ❌ Failed checks (1 error, 2 warnings)
|
This comment was marked as resolved.
This comment was marked as resolved.
|
@coderabbitai Please investigate the cause of the following issue using codegraph exploration and research, identify a fix and provide an AI coding agent prompt for the fix: |
This comment was marked as resolved.
This comment was marked as resolved.
|
@coderabbitai review |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@episodic/metrics_ports.py`:
- Line 9: Remove the forbidden future import by deleting the line "from
__future__ import annotations" wherever it appears (e.g., in the
episodic.metrics_ports and episodic.concurrent_interpreters modules) so the code
no longer uses the banned future import for Python >= 3.14; ensure no other code
relies on postponed evaluation (update type annotations to use standard runtime
annotations or string literals if necessary) and run the test/linter suite to
confirm no remaining references.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 224f9792-d912-4e95-b41c-6e5b2ec5b974
📒 Files selected for processing (12)
docs/developers-guide.mddocs/episodic-podcast-generation-system-design.mddocs/users-guide.mdepisodic/canonical/adapters/weighting.pyepisodic/concurrent_interpreters.pyepisodic/metrics_ports.pyepisodic/qa/chrono.pypyproject.tomltests/test_ingestion_weighting.pytests/test_interpreter_executor_lifecycle.pytests/test_interpreter_executor_observability.pytests/test_worker_interpreter_task_integration.py
💤 Files with no reviewable changes (3)
- tests/test_worker_interpreter_task_integration.py
- tests/test_interpreter_executor_observability.py
- tests/test_interpreter_executor_lifecycle.py
Describe how CPU-bound Celery task authors can opt into the interpreter-pool executor from within prefork worker processes. Clarify that interpreter-pool environment variables belong to task-level fan-out policy, not Celery worker pool selection, and cross-reference the Python 3.14 concurrent-interpreter decision from ADR-003.
Add executable worker-scaffold coverage for the documented CPU task interpreter-pool pattern. The tests exercise task-level use of `build_cpu_task_executor_from_environment()`, ordered mapping, environment flag handling, and inline fallback behaviour. Clarify executor ownership, shutdown, and task-level lifecycle guidance in both the adapter docstrings and worker documentation so future Celery task authors know where interpreter-pool fan-out belongs.
Move shared Celery worker scaffold test helpers into `tests/conftest.py` so `tests/test_worker_service_scaffold.py` stays below the module-line limit without changing pylint configuration. Keep the worker scaffold tests behaviourally unchanged by reusing the new fixture and helper symbols from the existing test module.
Add eager Celery task-body coverage for the interpreter-pool executor pattern so the documented integration point is exercised through the worker runtime boundary. Add Hypothesis properties for `map_ordered()` ordering across inline and interpreter-backed executors, and record that PR `#99` closed the Celery integration gap from issue `#66`.
Exercise the eager Celery interpreter-pool pattern without routing the mapped function through a test-only helper, so the task body contains the integration call directly. Constrain guest-bio property input to XML 1.0 text characters after Hypothesis found a persisted forbidden-codepoint example during the full commit gate.
Require CPU task executor selection to receive an explicit environment mapping and injectable capability detector. Keep environment reads at the task and composition boundaries instead of hiding them inside the builder. Hold the interpreter executor lifecycle lock through active mapping and shutdown so concurrent shutdown cannot race with `map_ordered()`. Cover active-map shutdown, post-shutdown mapping, and the documented Celery task integration path.
Expose environment and capability dependencies through the CPU executor builder API while keeping the existing default to `os.environ` for callers that do not provide an explicit mapping. Make interpreter-pool shutdown terminal and idempotent so later fan-out attempts fail instead of creating a new pool after shutdown. Cover active shutdown ordering, post-shutdown mapping, and repeated shutdown calls.
Add no-op metrics and clock ports to the interpreter CPU executor so task fan-out can report pool creation, map utilisation, map failures, shutdown failures, and shutdown latency without forcing a concrete backend. Cover lifecycle state transitions with Hypothesis-generated shutdown and mapping sequences, including map/shutdown races and terminal post-shutdown behaviour.
Add bounded counters for executor selection and interpreter-pool creation, and record explicit pool utilisation observations during successful maps. Broaden Hypothesis coverage for concurrent multi-map shutdown sequences and map-failure lifecycle transitions. Split observability tests into a focused module so lifecycle coverage stays below the module line limit.
Add `observe_value` for non-latency CPU executor measurements and keep `observe_latency_ms` reserved for latency observations. Move duplicated executor test helpers into shared test configuration, make shutdown idempotency explicit, and simplify the private worker runtime parser docstring.
Allow `build_cpu_task_executor_from_environment` to receive a metrics sink and pass it through to interpreter-pool executors. Keep executor selection counters on the same sink used for pool lifecycle observations. Remove the duplicate utilisation observation that repeated the batch size, and reuse the shared square helper in observability tests.
Convert `InterpreterPoolCapability` to a PEP 695 type alias and include it in `episodic.concurrent_interpreters.__all__` so callers can import the public builder signature type. Tighten parser and test-helper comments, and make executor cleanup in the observability test explicit for every builder return value.
Make the interpreter-pool capability probe and executor clock port private implementation hooks instead of exported production API. Document `CpuTaskExecutorMetricsPort` as the shared metrics integration point for executor selection, interpreter-pool lifecycle, map item counts, and shutdown latency.
Move `_capability_check` out of the public `build_cpu_task_executor_from_environment` signature into `_build_cpu_task_executor_from_environment`, keeping the public NumPy docstring aligned with its parameters. Tests that need an injectable capability check now call the private helper directly. Co-authored-by: Cursor <cursoragent@cursor.com>
- Retain and publish the remaining working-tree changes to keep the branch aligned. - Include docs updates for users/developers guidance and concurrency policy changes. - Include concurrent interpreter and weighting-related code updates already staged in this workspace. - Include new metrics ports module and chrono/pyproject supporting changes.
- Drop `from __future__ import annotations` from concurrent interpreter and metrics port modules. - Keep runtime-safe annotation typing in `episodic.metrics_ports` without requiring postponed evaluation.
f3f2d16 to
b710a05
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
docs/episodic-podcast-generation-system-design.md (1)
877-889:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winWrap this paragraph at 80 columns.
Lines 877, 878, 879, 881, 882, 884, 885, and 888 exceed the 80-column limit. Reflow the entire paragraph to comply.
Triage:
[type:docstyle]🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/episodic-podcast-generation-system-design.md` around lines 877 - 889, Reflow the paragraph describing the 2.4.1 roadmap item to wrap at 80 columns and fix all over-long lines; edit the text that mentions StructuredGenerationPlanner, LLMPort, ExecutionPlan, GenerationOrchestrationConfig, StructuredPlanningOrchestrator, ToolExecutorPort, ShowNotesToolExecutor, GuestBiosToolExecutor, RoutingToolExecutor, and LangGraph so each sentence is wrapped to <=80 characters without changing technical names or meaning and keep the same sequence of ideas (planner calls LLMPort for strict JSON -> parse to ExecutionPlan and record planning vs execution model -> orchestrator executes via ToolExecutorPort with the two concrete executors -> RoutingToolExecutor dispatches by ActionKind -> LangGraph wrapper remains in-process and limited to plan -> execute -> finish until later features land).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/episodic-podcast-generation-system-design.md`:
- Around line 552-555: Reflow the caption beginning "Caption: Speech synthesis
entity relationships." so no line exceeds 80 columns: break the sentence into
multiple lines (wrapping between words, not mid-word) so the full caption
"Pronunciation entries have one or more realizations; voice personas and
provider capabilities are selected for speech render requests; each speech
render request produces one or more speech render artefacts." is wrapped into
lines <=80 chars while preserving punctuation and meaning.
- Around line 1544-1546: The sentence starting with "resolve these bindings and
will snapshot selected revisions into ingestion-bound `source_documents`,
preserving reproducible TEI provenance while allowing independent document reuse
across jobs." exceeds 80 columns; reflow this sentence into multiple lines
wrapped at ~80 characters, preserving the inline code marker `source_documents`
and the original punctuation and meaning across the new lines.
- Around line 420-426: Paragraph exceeds the 80-column limit; reflow the entire
paragraph to wrap at 80 characters per line while preserving wording,
punctuation, and inline code/backticks for `TTSPort` and `DialogueSpeechPort`.
Keep the same sentences and meaning about the speech synthesis boundary,
single-speaker `TTSPort` for ordinary narration and partial regeneration, and
the optional `DialogueSpeechPort` for providers (e.g., Inworld Realtime,
ElevenLabs) that render multi‑speaker dialogue; ensure each new line is ≤80
columns and maintain readability and hyphenation where appropriate.
- Around line 720-721: The second sequence line exceeds 120 columns; shorten or
wrap the label for the message from DefaultWeightingStrategy to itself so the
code block stays ≤120 chars—e.g., replace
"build_cpu_task_executor_from_environment(os.environ, metrics=metrics)" with a
shortened label like "build_cpu_task_executor_from_environment(...,
metrics=metrics)" or split the message into two lines (keep the
Caller->>DefaultWeightingStrategy line unchanged and adjust the
DefaultWeightingStrategy->>DefaultWeightingStrategy message).
- Around line 494-499: The paragraph starting with "Alert on synthesis failures
and capability mismatches using aggregate metrics" exceeds the 80-column limit
and uses American "percent"; reflow this sentence into multiple lines under 80
characters and change "5 percent" to British "5 per cent", preserving the rest
of the wording (including the clause "page when the failure rate exceeds 5 per
cent over 15 minutes or five consecutive renders fail, warn when repeated
unsupported-capability diagnostics reach three in 30 minutes, and page when an
approved"). Ensure line breaks occur at natural phrase boundaries so readability
is maintained.
---
Outside diff comments:
In `@docs/episodic-podcast-generation-system-design.md`:
- Around line 877-889: Reflow the paragraph describing the 2.4.1 roadmap item to
wrap at 80 columns and fix all over-long lines; edit the text that mentions
StructuredGenerationPlanner, LLMPort, ExecutionPlan,
GenerationOrchestrationConfig, StructuredPlanningOrchestrator, ToolExecutorPort,
ShowNotesToolExecutor, GuestBiosToolExecutor, RoutingToolExecutor, and LangGraph
so each sentence is wrapped to <=80 characters without changing technical names
or meaning and keep the same sequence of ideas (planner calls LLMPort for strict
JSON -> parse to ExecutionPlan and record planning vs execution model ->
orchestrator executes via ToolExecutorPort with the two concrete executors ->
RoutingToolExecutor dispatches by ActionKind -> LangGraph wrapper remains
in-process and limited to plan -> execute -> finish until later features land).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 0a3c4edf-190b-45ca-92e6-5d63d53b09e1
📒 Files selected for processing (19)
docs/adr/adr-003-celery-worker-scaffold.mddocs/developers-guide.mddocs/episodic-podcast-generation-system-design.mddocs/execplans/upgrade-python-to-3-14-adopt-concurrent-interpreters.mddocs/users-guide.mdepisodic/canonical/adapters/weighting.pyepisodic/concurrent_interpreters.pyepisodic/metrics_ports.pyepisodic/qa/chrono.pyepisodic/worker/runtime.pyepisodic/worker/tasks.pypyproject.tomltests/conftest.pytests/test_ingestion_weighting.pytests/test_interpreter_executor.pytests/test_interpreter_executor_lifecycle.pytests/test_interpreter_executor_observability.pytests/test_worker_interpreter_task_integration.pytests/test_worker_service_scaffold.py
Summary
This branch documents the coupling point between the Celery worker scaffold and the Python 3.14 interpreter-pool executor so future CPU-bound task authors can find the intended intra-task fan-out path.
Closes #66.
Review walkthrough
build_cpu_task_executor_from_environment()andmap_ordered(...).Validation
make fmt: passed.make check-fmt: passed.make markdownlint: passed.make nixie: passed.make lint: passed.make typecheck: passed.make test: final rerun passed, reporting 477 passed and 3 skipped.Notes
make testattempts hit transientpytest-timeoutsetup errors in py-pglite-backed async fixtures. The affected tests passed when rerun directly before the final full-suite pass.Summary by Sourcery
Clarify how Celery worker runtime configuration relates to CPU-bound task interpreter-pool settings and document the intended task-level fan-out path via concurrent interpreters.
Documentation: