|
@@ -254,6 +254,10 @@ func (d *Deps) Process(ctx context.Context, body []byte, sig string) Result {
|
|
|
publishErr = d.CircuitBreaker.Do(ctx, func() error {
|
|
publishErr = d.CircuitBreaker.Do(ctx, func() error {
|
|
|
f, err := d.JetStream.PublishAsync(subject, payload)
|
|
f, err := d.JetStream.PublishAsync(subject, payload)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
|
|
+ // F2: submission-level failure (queue full, JS stopped, etc.)
|
|
|
|
|
+ if d.Metrics != nil {
|
|
|
|
|
+ d.Metrics.NATSPublishTotal.WithLabelValues("error").Inc()
|
|
|
|
|
+ }
|
|
|
return err
|
|
return err
|
|
|
}
|
|
}
|
|
|
fut = f
|
|
fut = f
|
|
@@ -265,6 +269,10 @@ func (d *Deps) Process(ctx context.Context, body []byte, sig string) Result {
|
|
|
} else {
|
|
} else {
|
|
|
fut, err := d.JetStream.PublishAsync(subject, payload)
|
|
fut, err := d.JetStream.PublishAsync(subject, payload)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
|
|
+ // F2: submission-level failure (no CB path).
|
|
|
|
|
+ if d.Metrics != nil {
|
|
|
|
|
+ d.Metrics.NATSPublishTotal.WithLabelValues("error").Inc()
|
|
|
|
|
+ }
|
|
|
publishErr = err
|
|
publishErr = err
|
|
|
} else if fut != nil {
|
|
} else if fut != nil {
|
|
|
go observeAsyncAck(fut, d, a.SourceID, subject, start)
|
|
go observeAsyncAck(fut, d, a.SourceID, subject, start)
|
|
@@ -358,10 +366,18 @@ func observeAsyncAck(fut nats.PubAckFuture, d *Deps, sourceID, subject string, s
|
|
|
}
|
|
}
|
|
|
select {
|
|
select {
|
|
|
case <-fut.Ok():
|
|
case <-fut.Ok():
|
|
|
|
|
+ // F2: broker accepted and persisted the message.
|
|
|
if d != nil && d.Metrics != nil {
|
|
if d != nil && d.Metrics != nil {
|
|
|
d.Metrics.PublishLatency.WithLabelValues(sourceID).Observe(time.Since(sentAt).Seconds())
|
|
d.Metrics.PublishLatency.WithLabelValues(sourceID).Observe(time.Since(sentAt).Seconds())
|
|
|
|
|
+ d.Metrics.NATSPublishTotal.WithLabelValues("ok").Inc()
|
|
|
}
|
|
}
|
|
|
case err := <-fut.Err():
|
|
case err := <-fut.Err():
|
|
|
|
|
+ // F2: broker rejected / timed out. This is the failure mode that
|
|
|
|
|
+ // the M11 NATS investigation missed (system looked healthy on
|
|
|
|
|
+ // the receive metric while publishes were silently failing).
|
|
|
|
|
+ if d != nil && d.Metrics != nil {
|
|
|
|
|
+ d.Metrics.NATSPublishTotal.WithLabelValues("error").Inc()
|
|
|
|
|
+ }
|
|
|
if d != nil && d.Logger != nil {
|
|
if d != nil && d.Logger != nil {
|
|
|
d.Logger.Warn("async publish failed", "subject", subject, "source_id", sourceID, "err", err)
|
|
d.Logger.Warn("async publish failed", "subject", subject, "source_id", sourceID, "err", err)
|
|
|
}
|
|
}
|