Skip to content

fix(gateway): offload all blocking atomic_json_write calls from async paths - #83951

Merged
kshitijk4poor merged 4 commits into
NousResearch:mainfrom
kshitijk4poor:salvage/channel-directory-fsync-off-loop
Aug 11, 2026
Merged

kshitijk4poor merged 4 commits into
NousResearch:mainfrom
kshitijk4poor:salvage/channel-directory-fsync-off-loop

Conversation

@kshitijk4poor

Copy link
Copy Markdown
Contributor

Summary

Completes the bug class from #83906 — offloads all remaining blocking atomic_json_write calls that run inside async gateway paths, using the same await asyncio.to_thread(...) pattern already established in build_channel_directory().

Root cause: atomic_json_write calls os.fsync(), which blocks until the write reaches stable storage. When called directly inside an async function on the gateway event loop, discord.py's heartbeat task waits behind the flush.

Changes

Sites intentionally left synchronous

Two atomic_json_write calls inside _stop_impl_body (shutdown path: _increment_restart_failure_counts and planned restart notification marker) are left synchronous — the event loop is draining/stopping during shutdown and offloading adds complexity for no benefit.

Validation

Before After
channel_directory tests 21 passed 21 passed
restart tests (5 files) 60 passed 60 passed
E2E (real imports) all 3 sites confirmed off-loop
ruff clean clean
py_compile OK OK

Closes #83906
Completes #60794

landaun and others added 4 commits August 11, 2026 20:07
atomic_json_write() calls os.fsync(), which blocks until the write
reaches stable storage. build_channel_directory() already offloads its
builders with asyncio.to_thread (NousResearch#60794) but still called the persist
step directly on the loop, so the Discord heartbeat waited on a disk
flush.
Mirrors test_discord_builder_runs_off_event_loop_thread. Verified to FAIL
against unpatched v0.19.0 and pass with the fix.
Completes the bug class from NousResearch#83906 — the same blocking fsync-on-event-loop
pattern existed in two more async gateway paths:

- slash_commands.py _handle_restart_command: two atomic_json_write calls
  for .restart_notify.json and .restart_last_processed.json were blocking
  on fsync inside an async function. Now offloaded via asyncio.to_thread.

- run.py _clear_restart_failure_count: called from
  _handle_message_with_agent (async, per-turn path) after a successful
  agent turn. Made the method async and offloaded the atomic_json_write
  call via asyncio.to_thread. Caller updated to await.

Shutdown-path calls in _stop_impl_body (_increment_restart_failure_counts,
planned restart notification marker) are intentionally left synchronous —
the event loop is draining/stopping and offloading adds complexity for no
benefit.
@alt-glitch alt-glitch added type/perf Performance improvement or optimization comp/gateway Gateway runner, session dispatch, delivery platform/discord Discord bot adapter P1 High — major feature broken, no workaround sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Aug 11, 2026
@alt-glitch

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Related: this is a broader competing repair to #83906. It includes that channel-directory offload and also moves the restart-path writes off the gateway event loop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P1 High — major feature broken, no workaround platform/discord Discord bot adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/perf Performance improvement or optimization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants