New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Exactly-once-processing not guaranteed by fire-and-forget NatsJetStreamMessage.inProgress() #1042
Comments
|
Thanks Scott! 1/ Agree, JetStream offers at-least-once delivery semantics for most stream configurations. It does appear that the docs intend to enable exactly-once-processing in the manner I am describing.
Granted, those both focus on the AckSync() capability. Unfortunately exactly-once processing behavior becomes unachievable/unreliable for messages whose processing time exceeds AckWait without introducing this proposed change. 2/ 3/ I'd also be happy to provide double-acking methods for the full suite of AckTypes along with asynchronous versions if they'd be on board with that. This ambition would likely touch the very externally-visible Message interface so I'd await guidance on what signatures, if any, you'd hope to add here. 4/ Notably, the reply subject of jetstream messages has a structure which encodes the message's metadata, including its monotonically increasing delivery count that seems like it could be used to decide whether an ACK is still valid or for a since-expired delivery attempt without any modification to the wire protocol. That is certainly tangent to this proposal, but I'd love if JetStream could distinguish between message receipts like SQS does with its notion of receipt handles. |
|
Observed behavior
The signature of NatsJetStreamMessage.inProgress() returns void. Its internal implementation merely publishes an Ack message to the reply subject of the NatsJetStreamMessage without waiting for confirmation from JetStream that the message's invisibility window has been extended.
A work-queue consumer expecting on exactly-once-processing delivery semantics and dutifully calling
inProgress()
while it works has no way of knowing whether its progress acks are being lost (either due to network partitions or the JetStream domain being otherwise temporarily unavailable.)Desired behavior
NatsJetStreamMessage.inProgress() should await confirmation from JetStream that the message invisibility window has been extended and enable the application to detect failure/uncertain delivery.
Ideally, NatsJetStreamMessage would expose a synchronous form of
inProgress()
that throws, and an asynchronous version that completes exceptionally if the AckProgress message isn't confirmed. (As well as similar methods for the other AckType variants if they're not already available like ackSync().)Server and client version
nats-server v2.10.4
Host environment
MacBook Pro, 2.6GHz 6-Core Intel Core i7, 16GB RAM
Steps to reproduce
1/ Launch "Hub" nats-server.
2/ Launch "Spoke" leafnode w/ JetStream
3/ Provision a work queue on the JetStream spoke.
4/ Launch a competing consumer which sends inProgress() acks every 5 seconds.
5/ Publish a message into the work queue.
6/ Temporarily stop the Spoke Jetstream server
After the consumer has started processing the message, Ctrl-C the JetStream Spoke nats-server, wait ~30 seconds for
ackWait(Duration.ofSeconds(15))
to expire, and start the process back up.7/ Observe that the message is redelivered to the competing consumer process while the first delivery is still being processed.
8/ An application can detect failure if they bypass the default impl of inProgress()
NATS JetStream responds to AckProgress messages if they include a reply topic.
The text was updated successfully, but these errors were encountered: