Skip to content

fix(discord): make typing lifecycle race-safe - #15

Open
emberian wants to merge 1 commit into
antra-tess:mainfrom
emberian:fix/typing-indicator-race
Open

emberian wants to merge 1 commit into
antra-tess:mainfrom
emberian:fix/typing-indicator-race

Conversation

@emberian

Copy link
Copy Markdown

Summary

  • register per-channel typing state before Discord requests begin
  • let stopTyping or a newer start invalidate in-flight startup work
  • clear superseded and shutdown intervals without leaving orphan refreshers
  • cover stop-during-start and repeated-start races with fake-timer tests

Root cause

The refresh interval was stored only after both channel fetch and initial sendTyping completed. A fast activation could stop typing during either await, see no tracked interval, and return; the older start then installed an interval that nothing could stop. Repeated starts could also overwrite the map entry while leaving the prior interval alive.

Verification

  • npm test -- --run src/discord/connector.typing.test.ts
  • npm test -- --run (474 tests)
  • git diff --check

Baseline tooling note

npm run build still reports the three existing GenerationConfig type errors in src/llm/membrane/adapter.ts on main. ESLint 9 also has no eslint.config file in the repository. Neither area is changed here.

@greptile-apps

greptile-apps Bot commented Aug 18, 2026

Copy link
Copy Markdown

Greptile Summary

This PR makes Discord typing state race-safe by registering per-channel state before asynchronous startup and using object identity to invalidate superseded work.

  • Clears an existing refresh interval before replacing its state.
  • Prevents stopped, superseded, or shutdown startup work from installing an interval.
  • Adds fake-timer coverage for stop-during-start and repeated-start races.

Confidence Score: 5/5

The PR appears safe to merge, with the changed lifecycle preventing orphan typing refresh intervals across the covered races.

State is registered before asynchronous Discord requests, checked after each await, and invalidated by stop, replacement, or close before an interval can be installed; the added tests exercise the principal stop and repeated-start races.

Important Files Changed

Filename Overview
src/discord/connector.ts Replaces late interval-only tracking with eagerly registered identity-token state, invalidating asynchronous startup across stop, replacement, and shutdown.
src/discord/connector.typing.test.ts Adds focused fake-timer tests showing that stop-during-fetch installs no refresher and repeated starts retain only the newest interval.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant Connector
    participant Discord
    Caller->>Connector: startTyping(channelId)
    Connector->>Connector: replace state token
    Connector->>Discord: fetch channel
    alt state was stopped or superseded
        Connector-->>Caller: return without interval
    else state remains current
        Connector->>Discord: sendTyping()
        alt state still current
            Connector->>Connector: install refresh interval
        else stopped or superseded
            Connector-->>Caller: return without interval
        end
    end
    Caller->>Connector: stopTyping(channelId)
    Connector->>Connector: clear interval and delete state
Loading

Reviews (1): Last reviewed commit: "fix(discord): make typing lifecycle race..." | Re-trigger Greptile

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant