fix(cron): deliver manual runs on gateway loop - #63586
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes manual/immediate cron job runs initiated from a live gateway session so that result delivery is executed on the gateway’s owning asyncio event loop (and with the live adapter map), matching the scheduled ticker path. This prevents async client misuse (notably mautrix/aiohttp for Matrix) that can occur when delivery is attempted from a standalone asyncio.run() context.
Changes:
- Pass the live gateway
adaptersmap and_gateway_loopintocron.scheduler.run_one_job()during_execute_job_now()by retrieving the running gateway runner viasys.modules["gateway.run"](when present). - Preserve the standalone/CLI behavior by falling back to
adapters=None, loop=Nonewhen the gateway context is absent. - Add regression tests covering both the live-gateway context and the standalone context for
_execute_job_now().
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| tools/cronjob_tools.py | Threads live gateway adapters + event loop into run_one_job() for manual runs to keep delivery loop-safe. |
| tests/tools/test_cronjob_run_immediate.py | Adds tests asserting manual runs pass live gateway context when available and remain standalone otherwise. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
teknium1
left a comment
There was a problem hiding this comment.
Thanks for routing manual cron runs through the scheduler’s loop-aware delivery path; current main still invokes run_one_job(job) without that context at tools/cronjob_tools.py:641.
Problems
tools/cronjob_tools.py:651always selectsrunner.adapters. In multiplex mode,gateway/run.py:2871-2877documents that this map is only for the default/active profile; secondary-profile adapters live inrunner._profile_adapters. A manual run from a secondary profile therefore still misses its live adapter context, which can reintroduce the standalone delivery path this change is intended to avoid.
Suggested changes
- Resolve the adapter map using the current profile runtime context, and add a secondary-profile regression alongside the default-gateway and standalone cases.
Automated hermes-sweeper review.
| gateway_module = sys.modules.get("gateway.run") | ||
| runner_ref = getattr(gateway_module, "_gateway_runner_ref", None) | ||
| runner = runner_ref() if callable(runner_ref) else None | ||
| adapters = getattr(runner, "adapters", None) if runner is not None else None |
There was a problem hiding this comment.
GatewayRunner.adapters is deliberately only the default/active profile map in multiplex mode; secondary adapters are in runner._profile_adapters (gateway/run.py:2871-2877). Resolve the map for the invoking profile here, otherwise a secondary-profile manual cron run still cannot use its own live adapter.
|
I reproduced this issue and carried this PR's original commit forward with Fly's authorship preserved as the first commit in #71132. The follow-up commit implements the maintainer-requested multiplex-profile handling and adds fail-closed coverage for:
The final targeted cron suite is 155/155 passing. I opened #71132 as the hardened continuation because I cannot update this contributor-owned branch directly; maintainers can treat it as the replacement while retaining this PR's contributor credit. |
|
Thanks @Fly-onlyone — this was the correct diagnosis and the correct fix: manual runs called |
Summary
Fixes #61495.
Why
cronjob(action="run")calledrun_one_job(job)without the gateway context. Matrix then reused a live mautrix/aiohttp adapter from a freshasyncio.run()loop and failed withTimeout context manager should be used inside a task. Scheduled gateway ticks already passadaptersandloop; this makes the manual path do the same.Tests
uv run --extra dev python -m pytest tests/tools/test_cronjob_run_immediate.py tests/tools/test_cronjob_tools.py -q(84 passed)uv run --extra dev python -m pytest tests/tools/test_windows_native_support.py -q(66 passed)uvx ruff check tools/cronjob_tools.py tests/tools/test_cronjob_run_immediate.py