@@ -21,6 +21,7 @@ import (
2121 "github.com/meridianhub/meridian/shared/pkg/idempotency"
2222 "github.com/meridianhub/meridian/shared/pkg/interceptors"
2323 "github.com/meridianhub/meridian/shared/platform/auth"
24+ "github.com/meridianhub/meridian/shared/platform/events"
2425 "github.com/prometheus/client_golang/prometheus"
2526 "github.com/prometheus/client_golang/prometheus/promhttp"
2627 "google.golang.org/grpc"
@@ -121,6 +122,29 @@ func run(logger *slog.Logger) error {
121122
122123 logger .Info ("dependency container initialized" )
123124
125+ // Initialize and start event outbox worker (if Kafka enabled)
126+ // TODO(tm:bian-alignment.14): Make worker config values (batch_size, poll_interval, max_retries)
127+ // configurable via environment variables for production tuning.
128+ var outboxWorker * events.Worker
129+ var workerCancel context.CancelFunc
130+ if container .KafkaProducer () != nil {
131+ workerConfig := events .DefaultWorkerConfig ("position-keeping" )
132+ outboxWorker = events .NewWorker (
133+ container .OutboxRepository ,
134+ container .KafkaProducer (),
135+ workerConfig ,
136+ logger ,
137+ )
138+
139+ // Start worker in background
140+ var workerCtx context.Context
141+ workerCtx , workerCancel = context .WithCancel (context .Background ())
142+ defer workerCancel () // Safety net; primary shutdown goes through explicit cancellation
143+ outboxWorker .Start (workerCtx )
144+ } else {
145+ logger .Info ("event outbox worker disabled (kafka not configured)" )
146+ }
147+
124148 // Create idempotency service
125149 var idempotencySvc idempotency.Service
126150 if container .RedisClient != nil {
@@ -274,6 +298,18 @@ func run(logger *slog.Logger) error {
274298 // Graceful shutdown
275299 logger .Info ("shutting down servers..." )
276300
301+ // Shutdown outbox worker before stopping servers
302+ // TODO(tm:bian-alignment.14): Add a shutdown timeout mechanism to prevent indefinite blocking
303+ // if the worker fails to stop gracefully (e.g., Kafka broker unreachable).
304+ if outboxWorker != nil {
305+ logger .Info ("stopping event outbox worker..." )
306+ if workerCancel != nil {
307+ workerCancel () // Cancel context first to signal worker to stop accepting new work
308+ }
309+ outboxWorker .Stop () // Blocks until current batch completes and Kafka flush finishes
310+ logger .Info ("event outbox worker stopped" )
311+ }
312+
277313 // Create shutdown context with timeout
278314 shutdownCtx , cancel := context .WithTimeout (context .Background (), config .Server .GracefulShutdownTimeout )
279315 defer cancel ()
0 commit comments