Description
Observed behavior
A regression appears to have been introduced between nats-server
v2.10.25 and v2.10.26 that affects how FilterSubjects
are handled for consumers configured with DeliverPolicy: DeliverAllPolicy
and ReplayPolicy: ReplayInstantPolicy
.
When a consumer uses FilterSubjects
containing both an exact subject and a related wildcard (e.g., ["stream.A", "stream.A.>"]
), it often fails to receive the expected historical messages from the stream upon startup if and only if there are no messages currently in the stream matching the wildcard filter (stream.A.>
) at the time the consumer starts.
If at least one message matching the wildcard filter (e.g., stream.A.child
) exists in the stream before the consumer starts, the consumer behaves correctly and receives the full history for both filters. If only messages matching the exact subject (stream.A
) exist, the bug manifests, and historical messages are often not delivered.
Newly published messages matching the filters are received correctly after startup, regardless of the initial state.
This behavior is inconsistent when the bug manifests; occasionally (though rarely), the consumer does receive the full history even without pre-existing wildcard matches, making it difficult to reliably reproduce without controlling the stream state precisely.
Configuration
- Stream: Configured with a
LimitsPolicy
(or other policy) to retain messages. The stream captures subjects matchingstream.>
. Subjects likestream.A
andstream.A.child
are published to it. - Consumer:
DeliverPolicy: DeliverAllPolicy
ReplayPolicy: ReplayInstantPolicy
AckPolicy: AckExplicitPolicy
(or potentially others)FilterSubjects: ["stream.A", "stream.A.>"]
(Problematic case)
Observed Behavior
- Condition: No messages matching
stream.A.>
exist in the stream. Only messages matchingstream.A
exist.- With
FilterSubjects: ["stream.A", "stream.A.>"]
:- Most of the time, the consumer starts but receives zero historical messages. It only receives new messages published after it started.
- Occasionally, the consumer starts and correctly receives the full history matching
stream.A
.
- With
- Condition: At least one message matching
stream.A.>
(e.g.,stream.A.child
) exists in the stream (along with messages matchingstream.A
).- With
FilterSubjects: ["stream.A", "stream.A.>"]
:- The consumer reliably starts and receives the full history matching both
stream.A
andstream.A.>
instantly, as expected.
- The consumer reliably starts and receives the full history matching both
- With
- With
FilterSubjects: ["stream.A"]
(regardless of stream content):- The consumer reliably starts and receives the full history matching
stream.A
instantly, as expected.
- The consumer reliably starts and receives the full history matching
Versions
This issue was reproduced locally by testing various nats-server
versions:
- v2.10.25: Works as expected (full history delivered reliably regardless of initial stream content).
- v2.10.26: Exhibits the bug under the conditions described above.
- v2.10.27 - v2.11.x: Also exhibit the bug under the conditions described above.
This strongly suggests a change introduced between v2.10.25 and v2.10.26 is responsible.
Expected behavior
When a consumer starts with DeliverAllPolicy
, ReplayInstantPolicy
, and FilterSubjects: ["stream.A", "stream.A.>"]
, it should reliably receive all historical messages present in the stream whose subjects match either stream.A
or stream.A.>
, regardless of whether messages matching stream.A.>
were present at the exact moment the consumer started.
Server and client version
nats-server v2.10.26+
nats.go v1.39.1
Host environment
Issue first detected from inconsistencies in k8s (via nats helm chart) after v2.11 upgrade from v2.10.25
Replicated locally on Apple MacBook Pro M4
Steps to reproduce
- Set up
nats-server
(v2.10.26 or later). - Create a stream e.g.
mystream
configured to retain messages on disk and capture subjects matchingstream.>
. - Scenario A (Bug Manifests):
- Publish several messages, only with subject
stream.A
. Ensure no messages exist with subjectstream.A.child
(or any other subject matchingstream.A.>
). - Create and run a consumer application connecting to
mystream
with:DeliverPolicy: DeliverAllPolicy
ReplayPolicy: ReplayInstantPolicy
FilterSubjects: ["stream.A", "stream.A.>"]
- Observe that the consumer often fails to log the historical
stream.A
messages immediately upon startup. Repeat consumer startup multiple times to observe inconsistency.
- Publish several messages, only with subject
- Scenario B (Works Correctly):
- Publish several messages with subject
stream.A
. - Publish at least one message with subject
stream.A.child
. - Create and run the same consumer application as in Step 3b.
- Observe that the consumer now reliably logs all historical messages (
stream.A
andstream.A.child
) immediately upon startup.
- Publish several messages with subject
- Verification: Modify the consumer to use
FilterSubjects: ["stream.A"]
and repeat Scenario A (Step 3a). Observe that history forstream.A
is now delivered reliably even withoutstream.A.child
messages present. - Regression Check: Optionally, downgrade
nats-server
to v2.10.25 and repeat Scenario A (Step 3a) with the originalFilterSubjects: ["stream.A", "stream.A.>"]
to confirm it works correctly even without pre-existingstream.A.child
messages.