Skip to content

fix(gateway): clean up Discord typing tasks on teardown - #23083

Closed
nazirulhafiy wants to merge 1 commit into
NousResearch:mainfrom
nazirulhafiy:fix/discord-typing-cleanup
Closed

fix(gateway): clean up Discord typing tasks on teardown#23083
nazirulhafiy wants to merge 1 commit into
NousResearch:mainfrom
nazirulhafiy:fix/discord-typing-cleanup

Conversation

@nazirulhafiy

@nazirulhafiy nazirulhafiy commented May 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes a Discord gateway teardown leak where typing indicator background tasks could survive disconnect() / cancel_background_tasks(), interfering with clean shutdown during gateway restarts or profile switches.

Changes

  • Track and clear Discord typing indicator tasks during adapter teardown.
  • Ensure disconnect() cancels typing tasks before shutting down.
  • Ensure cancel_background_tasks() clears Discord typing tasks before delegating to the base cleanup path.

Validation

  • python -m py_compile gateway/platforms/discord.py
  • Local full test run was checked; unrelated pre-existing failures remain outside this PR scope.

Notes

This PR is intentionally scoped to gateway/platforms/discord.py only.

@liuhao1024 liuhao1024 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR includes files that don't belong in the repository:

  1. Personal Obsidian notes from an iCloud path: "/Users/hafiy/Library/Mobile Documents/iCloud~md~obsidian/Documents/My Second Brain/Resources/Raw/2026-04-27 - signül on X.md" — this is a personal note about a tweet, not related to the hermes-agent codebase.

  2. .bak files: gateway/platforms/discord.py.bak, gateway/run.py.bak, hermes_cli/commands.py.bak — backup files should not be committed.

  3. docs/plans/2026-05-05-caveman-enforcement-plan.md — an internal implementation plan document that looks like it was accidentally staged.

Please remove these files from the PR and only include the actual code changes for the Discord typing indicator fix.

@nazirulhafiy
nazirulhafiy force-pushed the fix/discord-typing-cleanup branch from 6ddeb8c to a4719f2 Compare May 10, 2026 08:36
@nazirulhafiy

Copy link
Copy Markdown
Contributor Author

This PR includes files that don't belong in the repository:

  1. Personal Obsidian notes from an iCloud path: "/Users/hafiy/Library/Mobile Documents/iCloud~md~obsidian/Documents/My Second Brain/Resources/Raw/2026-04-27 - signül on X.md" — this is a personal note about a tweet, not related to the hermes-agent codebase.
  2. .bak files: gateway/platforms/discord.py.bak, gateway/run.py.bak, hermes_cli/commands.py.bak — backup files should not be committed.
  3. docs/plans/2026-05-05-caveman-enforcement-plan.md — an internal implementation plan document that looks like it was accidentally staged.

Please remove these files from the PR and only include the actual code changes for the Discord typing indicator fix.

Thank you. There were mistakes in submission and working to rectify.

@nazirulhafiy
nazirulhafiy force-pushed the fix/discord-typing-cleanup branch 2 times, most recently from 74a4b1a to 1e9bb6b Compare May 10, 2026 09:04
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have platform/discord Discord bot adapter comp/gateway Gateway runner, session dispatch, delivery labels May 10, 2026
@nazirulhafiy
nazirulhafiy force-pushed the fix/discord-typing-cleanup branch 2 times, most recently from fd92bfa to 8412058 Compare May 10, 2026 10:48
@nazirulhafiy
nazirulhafiy force-pushed the fix/discord-typing-cleanup branch from 19e199c to 38dc93a Compare May 20, 2026 23:28
@MKI13

MKI13 commented May 20, 2026

Copy link
Copy Markdown

Hermes autofix diagnosed the failing Contributor Attribution Check: the PR commit author email hafiy@Hafiy-Zakarias-MacBook-Air.local is not mapped in scripts/release.py.

I prepared the one-line fix and verified it locally:

  • Contributor Attribution Check reproduction: passes
  • python3 -m py_compile scripts/release.py: passes

I could not push directly to the contributor fork branch (Permission to nazirulhafiy/hermes-agent.git denied to MKI13), so I opened a PR against the contributor branch instead:
https://github.com/nazirulhafiy/hermes-agent/pull/1

@nazirulhafiy
nazirulhafiy force-pushed the fix/discord-typing-cleanup branch 2 times, most recently from d066073 to 125c2ed Compare May 21, 2026 00:47
@nazirulhafiy
nazirulhafiy force-pushed the fix/discord-typing-cleanup branch from 125c2ed to f60ec3f Compare May 21, 2026 01:08
@nazirulhafiy nazirulhafiy closed this by deleting the head repository May 27, 2026
nazirulhafiy pushed a commit to nazirulhafiy/hermes-agent that referenced this pull request Jun 23, 2026
The persistent per-channel typing loops spawned by send_typing() are not
tracked by BasePlatformAdapter's message-processing task registry, so on
gateway restart, exception path, or signal handler, they were never
cancelled. The typing endpoint's own 10-second timeout eventually cleared
the indicator on Discord's side, but Hermes would hang in a "typing..."
state for at least that long after every shutdown, with no way to abort
early.

This drains the entire _typing_tasks dict from two teardown points:

1. disconnect() — explicit operator-initiated close. Awaits
   _cancel_typing_tasks before tearing down voice clients and the
   discord.py client, so no in-flight loop survives the close.
2. cancel_background_tasks() — the base adapter's shutdown hook called
   from gateway/run.py on global shutdown. Drains Discord-specific
   tasks first, then defers to super() so the base cleanup still runs.

_cancel_typing_tasks() snapshots the dict, clears it immediately, cancels
each not-done task, and waits up to 2.0s for them to acknowledge the
cancel via asyncio.gather(..., return_exceptions=True). Anything still
alive at 2s logs a warning rather than blocking shutdown indefinitely —
the typing indicator on Discord's side will clear on its own after ~10s
even if the bot process is gone.

Resubmission of NousResearch#23083 (auto-closed 2026-05-27 due to personal files in
the diff). The original 1-file +39-line patch is preserved verbatim in
spirit; only the file path changed because commit cc8e5ec (2026-05-12,
pre-closure) migrated the Discord adapter from gateway/platforms/discord.py
to plugins/platforms/discord/adapter.py as a bundled plugin with full
Teams parity. The bug surface and fix logic are identical to the
original.

Repro path (from the original PR's context): on a healthy gateway, run
/ask in 2+ Discord DMs back-to-back. Force-kill the gateway process
(kill -9) or send SIGTERM. The "Hermes is typing..." indicator in any
chat that had not yet hit its stop_typing() call will linger for ~10s
after the bot process is gone. With this patch, _cancel_typing_tasks
runs from disconnect() and from the shutdown handler before the process
exits, so Discord sees the typing loop end promptly.
nazirulhafiy pushed a commit to nazirulhafiy/hermes-agent that referenced this pull request Jul 15, 2026
The persistent per-channel typing loops spawned by send_typing() are not
tracked by BasePlatformAdapter's message-processing task registry, so on
gateway restart, exception path, or signal handler, they were never
cancelled. The typing endpoint's own 10-second timeout eventually cleared
the indicator on Discord's side, but Hermes would hang in a "typing..."
state for at least that long after every shutdown, with no way to abort
early.

This drains the entire _typing_tasks dict from two teardown points:

1. disconnect() — explicit operator-initiated close. Awaits
   _cancel_typing_tasks before tearing down voice clients and the
   discord.py client, so no in-flight loop survives the close.
2. cancel_background_tasks() — the base adapter's shutdown hook called
   from gateway/run.py on global shutdown. Drains Discord-specific
   tasks first, then defers to super() so the base cleanup still runs.

_cancel_typing_tasks() snapshots the dict, clears it immediately, cancels
each not-done task, and waits up to 2.0s for them to acknowledge the
cancel via asyncio.gather(..., return_exceptions=True). Anything still
alive at 2s logs a warning rather than blocking shutdown indefinitely —
the typing indicator on Discord's side will clear on its own after ~10s
even if the bot process is gone.

Resubmission of NousResearch#23083 (auto-closed 2026-05-27 due to personal files in
the diff). The original 1-file +39-line patch is preserved verbatim in
spirit; only the file path changed because commit cc8e5ec (2026-05-12,
pre-closure) migrated the Discord adapter from gateway/platforms/discord.py
to plugins/platforms/discord/adapter.py as a bundled plugin with full
Teams parity. The bug surface and fix logic are identical to the
original.

Repro path (from the original PR's context): on a healthy gateway, run
/ask in 2+ Discord DMs back-to-back. Force-kill the gateway process
(kill -9) or send SIGTERM. The "Hermes is typing..." indicator in any
chat that had not yet hit its stop_typing() call will linger for ~10s
after the bot process is gone. With this patch, _cancel_typing_tasks
runs from disconnect() and from the shutdown handler before the process
exits, so Discord sees the typing loop end promptly.
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 P3 Low — cosmetic, nice to have platform/discord Discord bot adapter type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants