Sixth item of the v1.0.6 backlog. `RabbitMQEventBus.Publish` returned the
broker error but did not log it. Callers that wrap Publish in
fire-and-forget (`_ = eb.Publish(...)`) lost events with zero trace —
during an RMQ outage the backend would quietly shed work and operators
only noticed via downstream symptoms (missing notifications, stuck
async jobs, etc.).
Changes
* `Publish` now emits a structured ERROR with the exchange,
routing_key, payload_bytes, content_type, and message_id on every
broker failure. The function still returns the error so call-sites
that actually check it keep working exactly as before.
* The pre-existing "EventBus disabled" warning is kept but upgraded
with payload_bytes so dashboards can quantify drops when RMQ is
intentionally off (tests, dev without docker-compose --profile).
* `infrastructure/eventbus/rabbitmq.go:PublishEvent` (the newer,
event-sourcing variant) already had this pattern — this commit
brings the legacy path in line.
Tests
* 2 new tests in `rabbitmq_test.go`:
- disabled bus emits a single WARN with structured context and
returns EventBusUnavailableError
- nil logger path stays panic-free (legacy callers construct
bus without a logger)
* Broker-side failure path (closed channel) is not unit-tested here
because amqp091-go types don't expose a mockable channel without
spinning up a real RMQ — covered by the existing integration test
in `internal/integration/e2e_test.go`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
61 lines
1.9 KiB
Go
61 lines
1.9 KiB
Go
package eventbus
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
|
|
amqp "github.com/rabbitmq/amqp091-go"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
"go.uber.org/zap/zaptest/observer"
|
|
)
|
|
|
|
// TestPublish_DisabledBusLogsWarnAndReturnsError verifies the "EventBus
|
|
// disabled" path emits a WARN with message-size context and still returns
|
|
// an EventBusUnavailableError so callers that care can notice.
|
|
func TestPublish_DisabledBusLogsWarnAndReturnsError(t *testing.T) {
|
|
core, observed := observer.New(zapcore.WarnLevel)
|
|
eb := &RabbitMQEventBus{
|
|
config: &RabbitMQConfig{Enable: false},
|
|
logger: zap.New(core),
|
|
IsEnabled: false,
|
|
}
|
|
|
|
err := eb.Publish(context.Background(), "veza.events", "track.uploaded", false, false, amqp.Publishing{
|
|
Body: []byte(`{"track_id":"abc"}`),
|
|
})
|
|
|
|
var unavail *EventBusUnavailableError
|
|
require.True(t, errors.As(err, &unavail), "disabled bus must return EventBusUnavailableError")
|
|
|
|
entries := observed.All()
|
|
require.Len(t, entries, 1)
|
|
assert.Equal(t, zapcore.WarnLevel, entries[0].Level)
|
|
assert.Contains(t, entries[0].Message, "disabled")
|
|
|
|
// Verify structured context so dashboards can group drops by
|
|
// exchange+routing_key.
|
|
fields := map[string]interface{}{}
|
|
for _, f := range entries[0].Context {
|
|
fields[f.Key] = f
|
|
}
|
|
assert.Contains(t, fields, "exchange")
|
|
assert.Contains(t, fields, "routing_key")
|
|
assert.Contains(t, fields, "payload_bytes")
|
|
}
|
|
|
|
// TestPublish_NilLoggerIsAllowed guards against the legacy callers that
|
|
// construct an EventBus without a logger — the method must stay panic-free.
|
|
func TestPublish_NilLoggerIsAllowed(t *testing.T) {
|
|
eb := &RabbitMQEventBus{
|
|
config: &RabbitMQConfig{Enable: false},
|
|
logger: nil,
|
|
IsEnabled: false,
|
|
}
|
|
assert.NotPanics(t, func() {
|
|
_ = eb.Publish(context.Background(), "x", "y", false, false, amqp.Publishing{Body: []byte("hi")})
|
|
})
|
|
}
|