Make the merges consumer before the events consumer narrows, from the old one's ack floor, so no merge is lost to the change (issue 973)
mesh/merge-gate head 20e14872ef1e merged into trunk b0d489a86c23 — pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus…
mesh/repo-check head 20e14872ef1e merged into trunk b0d489a86c23 — fail: its merge-check.sh failed: --- FAIL: TestSSHClientOwnsTheOperatorsSSHConfig (0.07s…
mesh/delivery superseded: a newer head of the same pull request

This commit is contained in:
2026-10-17 12:33:18 +02:00
parent 5702187695
commit 20e14872ef
4 changed files with 75 additions and 15 deletions
+23
View File
@@ -343,6 +343,9 @@ func (j *JetStream) EnsureConsumer(c Consumer) error {
if c.FromNow {
want.DeliverPolicy = nats.DeliverNewPolicy
}
if from := j.ackFloorOfTheConsumerItTakesOver(c); from > 0 {
want.DeliverPolicy, want.OptStartSeq = nats.DeliverByStartSequencePolicy, from
}
if _, err := j.js.AddConsumer(c.Stream, want); err != nil {
return fmt.Errorf("creating consumer %s on %s: %w", c.Name, c.Stream, err)
}
@@ -352,6 +355,26 @@ func (j *JetStream) EnsureConsumer(c Consumer) error {
}
}
// ackFloorOfTheConsumerItTakesOver is the stream sequence a consumer made now starts at so as to lose nothing the
// consumer it takes over from (Consumer.TakesOverFrom) has not acknowledged: that consumer's ack floor plus one, when
// it exists and still filters this one's subject; zero otherwise.
func (j *JetStream) ackFloorOfTheConsumerItTakesOver(c Consumer) uint64 {
if c.TakesOverFrom == "" || len(c.Filters) != 1 {
return 0
}
have, err := j.js.ConsumerInfo(c.Stream, c.TakesOverFrom)
if err != nil {
return 0
}
filters := append([]string{have.Config.FilterSubject}, have.Config.FilterSubjects...)
for _, f := range filters {
if f == c.Filters[0] {
return have.AckFloor.Stream + 1
}
}
return 0
}
// ConsumerState is what a reset says about a consumer, before and after.
type ConsumerState struct {
DeliverPolicy string