Skip to content

feat: add SubscribeOpt.Receipt - #148

Open
mkuratczyk wants to merge 2 commits into
go-stomp:masterfrom
mkuratczyk:subscribe-receipt
Open

feat: add SubscribeOpt.Receipt#148
mkuratczyk wants to merge 2 commits into
go-stomp:masterfrom
mkuratczyk:subscribe-receipt

Conversation

@mkuratczyk

Copy link
Copy Markdown
Collaborator

This PR adds an option to request the receipt for the SUBSCRIBE command, so the client can wait until the subscription is confirmed.

@mkuratczyk
mkuratczyk requested a review from Zerpet September 3, 2026 07:48
Conn.Subscribe returns as soon as the SUBSCRIBE frame has been handed to
the I/O goroutine, so a message published right afterwards can be lost:
the server may not have finished creating the subscription (and any
underlying queue/binding) yet.

SubscribeOpt.Receipt asks for a RECEIPT on the SUBSCRIBE frame and waits
for it before returning, bounded by ConnOpt.SubscribeReceiptTimeout
(default 30s, ErrSubscribeReceiptTimeout on expiry).

The confirmation is routed via a new writeRequest.ReceiptC rather than
writeRequest.C, because for a SUBSCRIBE request C is already the
subscription's own frame channel, which the RECEIPT would otherwise
consume and close.

If the confirmation never arrives, the subscription is unsubscribed
again before returning the error. The SUBSCRIBE frame is already on its
way to the server at that point and the caller gets no handle back, so
otherwise the subscription's readLoop goroutine would leak, and any
message the server did deliver for it would eventually fill the
unreachable Subscription.C and block processLoop for every other
subscription on the connection.

Subscribe now also releases closeMutex once the request has been handed
over, instead of holding it across the receipt wait, so a slow server
does not stall every other operation on the connection. On the (rare)
path where the request never reaches processLoop, the frame channel is
closed so readLoop does not block on it forever.

Reply-to (temporary queue) subscriptions are never sent to the server -
processLoop registers the channel locally and drops the frame - so
nothing can produce a RECEIPT for them. The receipt header is dropped
for those rather than failing every such call after the timeout.

@Zerpet Zerpet left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Some feedback. I'm still thinking about Subscribe changes and abandon()

Comment thread subscribe_options.go Outdated
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.

2 participants