Skip to content

Conversation

MauriceVanVeen
Copy link
Member

@MauriceVanVeen MauriceVanVeen commented Jul 11, 2025

Up to this point JetStream has never been able to guarantee read-after-write or monotonic reads, unless the underlying stream was not replicated.

This ADR proposes a solution to both read-after-write and monotonic reads, for both Direct Get requests and consumers, that does not require all reads to go through replication.

Also clarified other ADRs that reference read-after-write.

Server PR: nats-io/nats-server#6970
Draft Go client implementation for read requests, consumers, and KV for both the old and new APIs (only object store is missing).

Resolves nats-io/nats-server#6557

@MauriceVanVeen MauriceVanVeen force-pushed the maurice/js-read-after-write branch from d1906d5 to abac5bd Compare July 11, 2025 13:22
Copy link
Member

@derekcollison derekcollison left a comment

Choose a reason for hiding this comment

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

In general really like this approach. I did have a question on deletes.

@MauriceVanVeen MauriceVanVeen force-pushed the maurice/js-read-after-write branch from abac5bd to 2848047 Compare July 14, 2025 07:33
@MauriceVanVeen MauriceVanVeen force-pushed the maurice/js-read-after-write branch 2 times, most recently from f2b0011 to 8753448 Compare July 21, 2025 13:39
@MauriceVanVeen MauriceVanVeen changed the title ADR-52: JetStream Read-after-Write ADR-53: JetStream Read-after-Write Jul 21, 2025
@MauriceVanVeen MauriceVanVeen force-pushed the maurice/js-read-after-write branch from 8753448 to 2ef9ef7 Compare July 22, 2025 15:25
@MauriceVanVeen MauriceVanVeen force-pushed the maurice/js-read-after-write branch 2 times, most recently from 5b42cf8 to 96874cf Compare July 29, 2025 15:14
neilalexander added a commit to nats-io/nats-server that referenced this pull request Jul 31, 2025
See [ADR: JetStream
Read-after-Write](nats-io/nats-architecture-and-design#358)
for context, problem statement, and design.

Resolves #6557

Signed-off-by: Maurice van Veen <[email protected]>
Signed-off-by: Maurice van Veen <[email protected]>
@MauriceVanVeen MauriceVanVeen force-pushed the maurice/js-read-after-write branch from 96874cf to 13abd6f Compare July 31, 2025 19:44
@MauriceVanVeen
Copy link
Member Author

MauriceVanVeen commented Jul 31, 2025

The server's read-after-write PR (nats-io/nats-server#6970) has been merged. Have updated this ADR's status to "Implemented".

Have also included a "Client Implementation" section that outlines the support required in the clients.

For reference, have created a draft Go client implementation. Please note it's incomplete, but it can be used as a reference. Have modeled that to what could be idiomatic in the Go client, other clients could improve to what's idiomatic there (the design is not strict on that).

Signed-off-by: Maurice van Veen <[email protected]>
@MauriceVanVeen MauriceVanVeen force-pushed the maurice/js-read-after-write branch from 13abd6f to f0aabb4 Compare July 31, 2025 20:42
adr/ADR-53.md Outdated

## Problem Statement

JetStream does NOT support read-after-write or monotonic reads. This can be especially problematic when
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe say before 2.12?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done, dcb9074:

JetStream does NOT support read-after-write or monotonic reads (prior to server version 2.12).

Signed-off-by: Maurice van Veen <[email protected]>
Copy link
Collaborator

@ripienaar ripienaar left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@jnmoyne jnmoyne left a comment

Choose a reason for hiding this comment

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

LGTM

@MauriceVanVeen MauriceVanVeen marked this pull request as draft August 15, 2025 11:20
@MauriceVanVeen
Copy link
Member Author

Parking this for a little bit, this feature will not be included in the upcoming 2.12 release.
It's something we can revisit early on in the 2.14 cycle.

One idea we've discussed a little already is instead of everything being opt-in and on a per-request basis, instead make it a stream-setting. Something like StreamConfig.ReadConsistency: Serializable / Linearizable. That would mean there doesn't need to be client or app-level changes (except for supporting the new stream field). When enabled, that could mean certain restrictions are placed such that the guarantees can be made. We could enable this by default on object store, but have it be an opt-in on KV and streams, etc.

Lots to figure out still, but need some more options so we can discuss which would be preferable.

@jpsugar-flow
Copy link

We're very interested in this feature. Right now we're minimizing the window by leaving direct get disabled, but this would let us turn everything on.

I'm curious if there's appetite for Spanner-like client-specified consistency requirements?

@MauriceVanVeen
Copy link
Member Author

MauriceVanVeen commented Aug 15, 2025

We're very interested in this feature. Right now we're minimizing the window by leaving direct get disabled, but this would let us turn everything on.

I'm curious if there's appetite for Spanner-like client-specified consistency requirements?

Thanks for sharing! Am not too familiar with Spanner myself, could you perhaps share a resource for the client-specified consistency requirements?

The primary options for stronger read consistency with JetStream would be that it's either specified client-side on a per-read-request basis ("for this specific request I need reads to be linearizable, versus by default they are eventually consistent with direct get"). Or specified top-level in the stream, which would mean all reads would be linearizable if specified as such.

Is this similar to what you're suggesting/expecting?

@jpsugar-flow
Copy link

jpsugar-flow commented Aug 15, 2025

Specifically Spanner has a "max staleness" bound: https://cloud.google.com/spanner/docs/reads#perform-stale-read

Was just an idle thought, not a feature request here. :)

@jpsugar-flow
Copy link

The primary options for stronger read consistency with JetStream would be that it's either specified client-side on a per-read-request basis ("for this specific request I need reads to be linearizable, versus by default they are eventually consistent with direct get"). Or specified top-level in the stream, which would mean all reads would be linearizable if specified as such.

That's what we're looking for, definitely. We don't necessarily need to force a leader round-trip; we often have a "last seen sequence" that we need the responder to be up-to-date to.

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.

KV Read-after-Write Consistency
6 participants