Repository navigation
Hedge stalled Firestore message writes from Twitch chat - #1754
Merged
Merged
Conversation
A Twitch chat message was dropped with "failed to write message to firestore: context deadline exceeded". createMessage retried transient failures within a 15s budget but had no per-attempt deadline, so one Create RPC that stalled consumed the whole budget and no retry ran. chatmessage.Create runs a message document Create and, since Creates are idempotent (an existing document counts as written), starts another attempt beside a pending one after 2s, or shortly after a transient failure, up to three attempts. The first to land wins; duplicate is reported only when a single attempt found the document already there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EzdqAWrbTMdtJutmK41coy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Error group
CJ-W7Oau86r1eg:createMessageretried transient Firestore errors within a 15s budget, but it had no per-attempt deadline. OneCreateRPC that stalled used up the whole 15s, no retry ever ran, and the chat message was dropped. The plaincontext deadline exceeded(not a gRPC status) is the outer budget expiring.Fix
This adds
chatmessage.Create, a hedged writer forchannels/{id}/messagesdocuments. It lives ininternal/chatmessage, which already holds what is shared by every writer of those documents.Createis idempotent: if the document already exists, it counts as written. So instead of waiting out a pending attempt,Createstarts another one beside it afterHedgeAfter(2s), or 100–200ms after a transient failure. It allows up toMaxAttempts(3), and the first attempt to land wins. Remaining attempts are canceled on return.AlreadyExists, that may be the stalled attempt's own write. Soduplicateis reported only when a single attempt ran, which keeps thechatmetricsduplicate counts honest.PermissionDenied) return immediately. When the budget expires, the result is the last transient error, or the context error if there was none.handler.createMessagekeeps its 15s budget and now delegates tochatmessage.Create.writereadsduplicatefrom it instead of sniffing the error inside the closure.A follow-up stacked PR applies the same writer to the Kick webhook (
CMPH0OLm48j3xgE).Tests
TestCreateMessageSurvivesStalledAttemptreproduces the production failure: the first attempt stalls and a second would succeed. Onmainit fails withcalls=1 err=context deadline exceeded after 15s. Here it succeeds after about 2s.chatmessage.TestCreate(undersynctest) covers:go test -race -count=3passes forinternal/chatmessageandinternal/handler.go test ./...passes except theinternal/youtubelive tests, which need youtube.com (blocked in the sandbox where this was developed).Generated by Claude Code