fix(app): support register_lifespan_task as a decorator#6343
fix(app): support register_lifespan_task as a decorator#6343BABTUNA wants to merge 2 commits intoreflex-dev:mainfrom
Conversation
Greptile SummaryThis PR fixes Confidence Score: 5/5Safe to merge β the logic is correct, tests cover both decorator patterns, and internal registration behavior is unchanged. Both decorator patterns work correctly: the plain case returns the original callable and stores it directly, and the kwargs case returns a No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant U as User Code
participant R as register_lifespan_task
participant T as _lifespan_tasks dict
Note over U,T: Plain decorator usage
U->>R: @app.register_lifespan_task (task=fn)
R->>R: task is not None β proceed
R->>R: check _lifespan_tasks_started
R->>R: check isgeneratorfunction
R->>T: _lifespan_tasks[fn] = None
R-->>U: returns fn (original callable)
Note over U,T: Decorator-with-kwargs usage
U->>R: @app.register_lifespan_task(timeout=10)
R->>R: task is None β return partial(register_lifespan_task, timeout=10)
R-->>U: returns partial (decorator)
U->>R: partial(fn) β register_lifespan_task(fn, timeout=10)
R->>R: check _lifespan_tasks_started
R->>R: check isgeneratorfunction
R->>R: registered_task = partial(fn, timeout=10)
R->>T: _lifespan_tasks[registered_task] = None
R-->>U: returns fn (original callable)
Reviews (1): Last reviewed commit: "Support register_lifespan_task decorator..." | Re-trigger Greptile |
Replace the compound return-type union with @overload stubs + a TypeVar so decorated functions keep their exact signature. Reject asyncio.Task + kwargs early with a clear error (previously would silently build a broken partial), which also eliminates the two pyright ignores. Swap the test's implementation-detail asserts (functools.partial internals) for a behavioral call-the-task check.
β’ ### All Submissions:
github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) file?
Requests for the desired
changed?
Type of change
New Feature Submission:
Changes To Core Features:
like us to include them?
Description
This fixes
App.register_lifespan_taskso it can be used as a decorator.Before this change:
@app.register_lifespan_taskbound the function name toNonebecausethe method did not return the task.
@app.register_lifespan_task(timeout=10)raised because the methodrequired
taskas a positional arg.What changed:
register_lifespan_tasknow acceptstask: Callable | asyncio.Task | None = None.functools.partial(...).wrapped
functools.partialthat is stored in_lifespan_tasks.Tests
Added:
tests/units/app_mixins/test_lifespan.pytest_register_lifespan_task_can_be_used_as_decoratortest_register_lifespan_task_with_kwargs_can_be_used_as_decoratorValidation run:
uv run pytest tests/units/app_mixins/test_lifespan.py -quv run ruff check reflex/app_mixins/lifespan.py tests/units/app_mixins/ test_lifespan.pyCloses #6330