Skip to content

Add OutChanCapacity, and let the session wait for the writer when the outgoing buffer is full - #784

Open
Nu0bG wants to merge 1 commit into
quickfixgo:mainfrom
Nu0bG:out-chan-capacity
Open

Nu0bG wants to merge 1 commit into
quickfixgo:mainfrom
Nu0bG:out-chan-capacity

Conversation

@Nu0bG

@Nu0bG Nu0bG commented Oct 14, 2026

Copy link
Copy Markdown

Closes #783.

Adds OutChanCapacity, the outgoing counterpart of InChanCapacity (#736). It also stops the session loop from busy-spinning while that buffer is full.

Changes

  • config.OutChanCapacity, SessionSettings.OutChanCapacity. The default is 0, an unbuffered channel and today's behaviour. A negative value is refused, as for InChanCapacity.

  • initiator.go, acceptor.go. msgOut is made with that capacity, and the writer is given the session's messageTaken.

  • writeLoop takes an optional taken func(). It calls it after it takes each message and before it writes it: the channel has room from that moment.

  • session.sendQueued. With a buffer, a send that finds it full calls waitForRoom:

    • it sets waitingForRoom and tries the send once more;
    • if that try fails too, the session returns without notifyMessageOut();
    • messageTaken clears the flag with a compare-and-swap and wakes the session once.

    The flag is set before the second try, so a take in between is either seen by that try or wakes the session. With no buffer the path is unchanged: a failed send still calls notifyMessageOut().

  • Disconnected (messageOut == nil). With a buffer, the session no longer comes round for the queued messages. They wait for the next logon, as with any other queued message.

Tests

New, in out_chan_capacity_test.go:

  • an unbuffered channel still comes round at once;
  • with a full buffer, the session is not woken until the writer takes a message, and a take nobody waits for wakes nothing;
  • writeLoop calls taken once per message, in order;
  • 2,000 messages to a slow writer (50 µs each) through a buffer of 4, under -race: every message arrives in order, and the loop comes round no more times than there are messages;
  • the setting: unset is 0, 256 is taken, -1 is refused.

Checks run

On macOS with Go 1.24.2:

  • go test -race ./...: every package passes but log/mongo. That one panics in TearDownTest without MONGODB_TEST_CXN, on main as well.
  • go vet ./... passes.
  • golangci-lint v1.64.6, the version the Makefile pins: no findings.
  • gofmt -l: nothing listed.

The acceptance suite under _test was not run.

…waits for the writer when it is full

With a buffer, a send that finds the channel full no longer makes the session loop come round at once. The session sets a flag and the writer wakes it when it takes a message. Unset (0), the channel stays unbuffered and the behaviour is unchanged.
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.

The session loop busy-spins while the outgoing channel is full

1 participant