Skip to content

fix(fetcher/idle): make mailbox-update channel send non-blocking#1270

Open
mvanhorn wants to merge 1 commit into
floatpane:masterfrom
mvanhorn:osc/1124-idle-non-blocking-send
Open

fix(fetcher/idle): make mailbox-update channel send non-blocking#1270
mvanhorn wants to merge 1 commit into
floatpane:masterfrom
mvanhorn:osc/1124-idle-non-blocking-send

Conversation

@mvanhorn
Copy link
Copy Markdown
Contributor

@mvanhorn mvanhorn commented May 11, 2026

What?

fetcher/idle.go -- the Mailbox callback in idleOnce now uses a non-blocking send on the mailboxUpdates channel via select { case mailboxUpdates <- *data.NumMessages: default: }. The early-return for data.NumMessages == nil is hoisted to keep the select body small.

Closes #1124

Why?

The callback runs on the IMAP socket-reader goroutine. The prior synchronous send blocks the callback whenever the 32-buffered channel is full, which stalls the socket reader itself. If the consuming select happens to be blocked (the stop-channel close race the issue describes), IDLE quietly hangs until the connection times out.

mailboxUpdates is a status-only channel: the consumer at line 191 only cares whether the latest count exceeds prevExists. Any value older than the most recent is already obsolete, so dropping a stale update on a full channel is harmless - the next callback fires with the current count and delivers it. The synchronous send traded nothing for the guaranteed deadlock in the failure mode the issue describes; the non-blocking send keeps the socket reader alive at the cost of a stale buffered value that would have been overwritten anyway.

go build ./fetcher/... clean, go vet ./fetcher/... clean, go test ./fetcher/... -> ok github.com/floatpane/matcha/fetcher 0.468s. Eleven lines inside one closure; no public API change, no new dependency.

The Mailbox callback runs on the IMAP socket-reader goroutine. The
prior synchronous send on the 32-buffered mailboxUpdates channel
blocked the socket reader whenever the channel filled up, and if the
consuming select happened to be blocked (e.g. racing with stop-channel
close ordering) IDLE quietly hung until the connection timed out.

Switch to a non-blocking send with a default branch so the callback
never blocks. Dropping an older count is safe: the consumer only acts
on the latest value via prevExists tracking, so any dropped update is
superseded by the next one that lands.

Closes floatpane#1124
@mvanhorn mvanhorn requested a review from a team as a code owner May 11, 2026 07:42
@floatpanebot floatpanebot added bug Something isn't working ci CI / build pipeline labels May 11, 2026
Copy link
Copy Markdown
Member

@floatpanebot floatpanebot left a comment

Choose a reason for hiding this comment

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

Hi @mvanhorn! Please fix the following issues with your PR:

  • Title: Does not follow conventional commits (e.g., feat: added something, fix(core): resolved crash).
  • Title: Is too long (64 characters). The PR title must be strictly under 40 characters.

@floatpanebot floatpanebot added the area/fetcher IMAP fetch / IDLE / search label May 11, 2026
@steveevansdev
Copy link
Copy Markdown
Member

scope should not contain /, regex fails, @mvanhorn

Copy link
Copy Markdown
Member

@floatpanebot floatpanebot left a comment

Choose a reason for hiding this comment

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

Hi @floatpanebot! Please fix the following issues with your PR:

  • Title: Does not follow conventional commits (e.g., feat: added something, fix(core): resolved crash).
  • Title: Is too long (64 characters). The PR title must be strictly under 40 characters.

@andrinoff andrinoff added the size/S Diff: 11–50 lines label May 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/fetcher IMAP fetch / IDLE / search bug Something isn't working ci CI / build pipeline size/S Diff: 11–50 lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: Bidirectional 'else if found && err == nil' patterns hide partial state in IDLE handler

4 participants