detached 1bfe21e

fix(concurrency): pass context to EventHandler.Handle for cancellation

Change EventHandler interface to Handle(ctx, event) so the event bus can
cancel long-running handlers via context.WithTimeout instead of leaking
goroutines with time.After.
commit
1bfe21e89cf05fe92374de03eb98f3ad787a1093
author
brice · · 2026-02-06 06:12 UTC
parent
285d237
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
9 files · +70 -56
M internal/adapters/out/eventbus/inmemory.go +6 -2
@@ -189,13 +189,16 @@ func (bus *InMemory) handleEvent(event domain.Event) {
189189 h := handler // shadow loop variable for goroutine capture
190190 start := time.Now()
191191
192+ ctx, cancel := context.WithTimeout(bus.ctx, 30*time.Second)
193+
192194 done := make(chan error, 1)
193195 go func() {
194- done <- h.Handle(event)
196+ done <- h.Handle(ctx, event)
195197 }()
196198
197199 select {
198200 case err := <-done:
201+ cancel()
199202 if err != nil {
200203 bus.log.Error().
201204 Str(zerowrap.FieldLayer, "adapter").
@@ -215,7 +218,8 @@ func (bus *InMemory) handleEvent(event domain.Event) {
215218 Dur(zerowrap.FieldDuration, time.Since(start)).
216219 Msg("event handled successfully")
217220 }
218- case <-time.After(30 * time.Second):
221+ case <-ctx.Done():
222+ cancel()
219223 bus.log.Warn().
220224 Str(zerowrap.FieldLayer, "adapter").
221225 Str(zerowrap.FieldAdapter, "eventbus").
@@ -189,13 +189,16 @@ func (bus *InMemory) handleEvent(event domain.Event) {
189 h := handler // shadow loop variable for goroutine capture189 h := handler // shadow loop variable for goroutine capture
190 start := time.Now()190 start := time.Now()
191 191
192+ ctx, cancel := context.WithTimeout(bus.ctx, 30*time.Second)
193+
192 done := make(chan error, 1)194 done := make(chan error, 1)
193 go func() {195 go func() {
194- done <- h.Handle(event)196+ done <- h.Handle(ctx, event)
195 }()197 }()
196 198
197 select {199 select {
198 case err := <-done:200 case err := <-done:
201+ cancel()
199 if err != nil {202 if err != nil {
200 bus.log.Error().203 bus.log.Error().
201 Str(zerowrap.FieldLayer, "adapter").204 Str(zerowrap.FieldLayer, "adapter").
@@ -215,7 +218,8 @@ func (bus *InMemory) handleEvent(event domain.Event) {
215 Dur(zerowrap.FieldDuration, time.Since(start)).218 Dur(zerowrap.FieldDuration, time.Since(start)).
216 Msg("event handled successfully")219 Msg("event handled successfully")
217 }220 }
218- case <-time.After(30 * time.Second):221+ case <-ctx.Done():
222+ cancel()
219 bus.log.Warn().223 bus.log.Warn().
220 Str(zerowrap.FieldLayer, "adapter").224 Str(zerowrap.FieldLayer, "adapter").
221 Str(zerowrap.FieldAdapter, "eventbus").225 Str(zerowrap.FieldAdapter, "eventbus").
M internal/boundaries/out/eventbus.go +3 -1
@@ -1,12 +1,14 @@
11 package out
22
33 import (
4+ "context"
5+
46 "github.com/bnema/gordon/internal/domain"
57 )
68
79 // EventHandler defines the contract for handling events.
810 type EventHandler interface {
9- Handle(event domain.Event) error
11+ Handle(ctx context.Context, event domain.Event) error
1012 CanHandle(eventType domain.EventType) bool
1113 }
1214
@@ -1,12 +1,14 @@
1 package out1 package out
2 2
3 import (3 import (
4+ "context"
5+
4 "github.com/bnema/gordon/internal/domain"6 "github.com/bnema/gordon/internal/domain"
5 )7 )
6 8
7 // EventHandler defines the contract for handling events.9 // EventHandler defines the contract for handling events.
8 type EventHandler interface {10 type EventHandler interface {
9- Handle(event domain.Event) error11+ Handle(ctx context.Context, event domain.Event) error
10 CanHandle(eventType domain.EventType) bool12 CanHandle(eventType domain.EventType) bool
11 }13 }
12 14
M internal/boundaries/out/mocks/mock_event_handler.go +18 -10
@@ -5,6 +5,8 @@
55 package mocks
66
77 import (
8+ "context"
9+
810 "github.com/bnema/gordon/internal/domain"
911 mock "github.com/stretchr/testify/mock"
1012 )
@@ -88,16 +90,16 @@ func (_c *MockEventHandler_CanHandle_Call) RunAndReturn(run func(eventType domai
8890 }
8991
9092 // Handle provides a mock function for the type MockEventHandler
91-func (_mock *MockEventHandler) Handle(event domain.Event) error {
92- ret := _mock.Called(event)
93+func (_mock *MockEventHandler) Handle(ctx context.Context, event domain.Event) error {
94+ ret := _mock.Called(ctx, event)
9395
9496 if len(ret) == 0 {
9597 panic("no return value specified for Handle")
9698 }
9799
98100 var r0 error
99- if returnFunc, ok := ret.Get(0).(func(domain.Event) error); ok {
100- r0 = returnFunc(event)
101+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Event) error); ok {
102+ r0 = returnFunc(ctx, event)
101103 } else {
102104 r0 = ret.Error(0)
103105 }
@@ -110,19 +112,25 @@ type MockEventHandler_Handle_Call struct {
110112 }
111113
112114 // Handle is a helper method to define mock.On call
115+// - ctx context.Context
113116 // - event domain.Event
114-func (_e *MockEventHandler_Expecter) Handle(event interface{}) *MockEventHandler_Handle_Call {
115- return &MockEventHandler_Handle_Call{Call: _e.mock.On("Handle", event)}
117+func (_e *MockEventHandler_Expecter) Handle(ctx interface{}, event interface{}) *MockEventHandler_Handle_Call {
118+ return &MockEventHandler_Handle_Call{Call: _e.mock.On("Handle", ctx, event)}
116119 }
117120
118-func (_c *MockEventHandler_Handle_Call) Run(run func(event domain.Event)) *MockEventHandler_Handle_Call {
121+func (_c *MockEventHandler_Handle_Call) Run(run func(ctx context.Context, event domain.Event)) *MockEventHandler_Handle_Call {
119122 _c.Call.Run(func(args mock.Arguments) {
120- var arg0 domain.Event
123+ var arg0 context.Context
121124 if args[0] != nil {
122- arg0 = args[0].(domain.Event)
125+ arg0 = args[0].(context.Context)
126+ }
127+ var arg1 domain.Event
128+ if args[1] != nil {
129+ arg1 = args[1].(domain.Event)
123130 }
124131 run(
125132 arg0,
133+ arg1,
126134 )
127135 })
128136 return _c
@@ -133,7 +141,7 @@ func (_c *MockEventHandler_Handle_Call) Return(err error) *MockEventHandler_Hand
133141 return _c
134142 }
135143
136-func (_c *MockEventHandler_Handle_Call) RunAndReturn(run func(event domain.Event) error) *MockEventHandler_Handle_Call {
144+func (_c *MockEventHandler_Handle_Call) RunAndReturn(run func(ctx context.Context, event domain.Event) error) *MockEventHandler_Handle_Call {
137145 _c.Call.Return(run)
138146 return _c
139147 }
@@ -5,6 +5,8 @@
5 package mocks5 package mocks
6 6
7 import (7 import (
8+ "context"
9+
8 "github.com/bnema/gordon/internal/domain"10 "github.com/bnema/gordon/internal/domain"
9 mock "github.com/stretchr/testify/mock"11 mock "github.com/stretchr/testify/mock"
10 )12 )
@@ -88,16 +90,16 @@ func (_c *MockEventHandler_CanHandle_Call) RunAndReturn(run func(eventType domai
88 }90 }
89 91
90 // Handle provides a mock function for the type MockEventHandler92 // Handle provides a mock function for the type MockEventHandler
91-func (_mock *MockEventHandler) Handle(event domain.Event) error {93+func (_mock *MockEventHandler) Handle(ctx context.Context, event domain.Event) error {
92- ret := _mock.Called(event)94+ ret := _mock.Called(ctx, event)
93 95
94 if len(ret) == 0 {96 if len(ret) == 0 {
95 panic("no return value specified for Handle")97 panic("no return value specified for Handle")
96 }98 }
97 99
98 var r0 error100 var r0 error
99- if returnFunc, ok := ret.Get(0).(func(domain.Event) error); ok {101+ if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Event) error); ok {
100- r0 = returnFunc(event)102+ r0 = returnFunc(ctx, event)
101 } else {103 } else {
102 r0 = ret.Error(0)104 r0 = ret.Error(0)
103 }105 }
@@ -110,19 +112,25 @@ type MockEventHandler_Handle_Call struct {
110 }112 }
111 113
112 // Handle is a helper method to define mock.On call114 // Handle is a helper method to define mock.On call
115+// - ctx context.Context
113 // - event domain.Event116 // - event domain.Event
114-func (_e *MockEventHandler_Expecter) Handle(event interface{}) *MockEventHandler_Handle_Call {117+func (_e *MockEventHandler_Expecter) Handle(ctx interface{}, event interface{}) *MockEventHandler_Handle_Call {
115- return &MockEventHandler_Handle_Call{Call: _e.mock.On("Handle", event)}118+ return &MockEventHandler_Handle_Call{Call: _e.mock.On("Handle", ctx, event)}
116 }119 }
117 120
118-func (_c *MockEventHandler_Handle_Call) Run(run func(event domain.Event)) *MockEventHandler_Handle_Call {121+func (_c *MockEventHandler_Handle_Call) Run(run func(ctx context.Context, event domain.Event)) *MockEventHandler_Handle_Call {
119 _c.Call.Run(func(args mock.Arguments) {122 _c.Call.Run(func(args mock.Arguments) {
120- var arg0 domain.Event123+ var arg0 context.Context
121 if args[0] != nil {124 if args[0] != nil {
122- arg0 = args[0].(domain.Event)125+ arg0 = args[0].(context.Context)
126+ }
127+ var arg1 domain.Event
128+ if args[1] != nil {
129+ arg1 = args[1].(domain.Event)
123 }130 }
124 run(131 run(
125 arg0,132 arg0,
133+ arg1,
126 )134 )
127 })135 })
128 return _c136 return _c
@@ -133,7 +141,7 @@ func (_c *MockEventHandler_Handle_Call) Return(err error) *MockEventHandler_Hand
133 return _c141 return _c
134 }142 }
135 143
136-func (_c *MockEventHandler_Handle_Call) RunAndReturn(run func(event domain.Event) error) *MockEventHandler_Handle_Call {144+func (_c *MockEventHandler_Handle_Call) RunAndReturn(run func(ctx context.Context, event domain.Event) error) *MockEventHandler_Handle_Call {
137 _c.Call.Return(run)145 _c.Call.Return(run)
138 return _c146 return _c
139 }147 }
M internal/usecase/container/autoroute.go +2 -2
@@ -60,8 +60,8 @@ func (h *AutoRouteHandler) WithEnvExtractor(extractor EnvFileExtractor, envDir s
6060 }
6161
6262 // Handle handles an image.pushed event and creates routes from labels.
63-func (h *AutoRouteHandler) Handle(event domain.Event) error {
64- ctx := zerowrap.CtxWithFields(h.ctx, map[string]any{
63+func (h *AutoRouteHandler) Handle(ctx context.Context, event domain.Event) error {
64+ ctx = zerowrap.CtxWithFields(ctx, map[string]any{
6565 zerowrap.FieldLayer: "usecase",
6666 zerowrap.FieldHandler: "AutoRouteHandler",
6767 zerowrap.FieldEvent: string(event.Type),
@@ -60,8 +60,8 @@ func (h *AutoRouteHandler) WithEnvExtractor(extractor EnvFileExtractor, envDir s
60 }60 }
61 61
62 // Handle handles an image.pushed event and creates routes from labels.62 // Handle handles an image.pushed event and creates routes from labels.
63-func (h *AutoRouteHandler) Handle(event domain.Event) error {63+func (h *AutoRouteHandler) Handle(ctx context.Context, event domain.Event) error {
64- ctx := zerowrap.CtxWithFields(h.ctx, map[string]any{64+ ctx = zerowrap.CtxWithFields(ctx, map[string]any{
65 zerowrap.FieldLayer: "usecase",65 zerowrap.FieldLayer: "usecase",
66 zerowrap.FieldHandler: "AutoRouteHandler",66 zerowrap.FieldHandler: "AutoRouteHandler",
67 zerowrap.FieldEvent: string(event.Type),67 zerowrap.FieldEvent: string(event.Type),
M internal/usecase/container/autoroute_test.go +8 -8
@@ -368,7 +368,7 @@ func TestAutoRouteHandler_Handle_DisabledAutoRoute(t *testing.T) {
368368 },
369369 }
370370
371- err := handler.Handle(event)
371+ err := handler.Handle(context.Background(), event)
372372
373373 assert.NoError(t, err)
374374 }
@@ -389,7 +389,7 @@ func TestAutoRouteHandler_Handle_InvalidPayload(t *testing.T) {
389389 Data: "invalid payload type",
390390 }
391391
392- err := handler.Handle(event)
392+ err := handler.Handle(context.Background(), event)
393393
394394 // Handler skips invalid payload, doesn't error
395395 assert.NoError(t, err)
@@ -415,7 +415,7 @@ func TestAutoRouteHandler_Handle_EmptyManifest(t *testing.T) {
415415 },
416416 }
417417
418- err := handler.Handle(event)
418+ err := handler.Handle(context.Background(), event)
419419
420420 assert.NoError(t, err)
421421 }
@@ -475,7 +475,7 @@ func TestAutoRouteHandler_Handle_CreatesNewRoute(t *testing.T) {
475475 },
476476 }
477477
478- err := handler.Handle(event)
478+ err := handler.Handle(context.Background(), event)
479479
480480 assert.NoError(t, err)
481481 }
@@ -537,7 +537,7 @@ func TestAutoRouteHandler_Handle_UpdatesExistingRoute(t *testing.T) {
537537 },
538538 }
539539
540- err := handler.Handle(event)
540+ err := handler.Handle(context.Background(), event)
541541
542542 assert.NoError(t, err)
543543 }
@@ -589,7 +589,7 @@ func TestAutoRouteHandler_Handle_NoUpdateIfSameImage(t *testing.T) {
589589 },
590590 }
591591
592- err := handler.Handle(event)
592+ err := handler.Handle(context.Background(), event)
593593
594594 assert.NoError(t, err)
595595 }
@@ -636,7 +636,7 @@ func TestAutoRouteHandler_Handle_NoDomainLabel(t *testing.T) {
636636 },
637637 }
638638
639- err := handler.Handle(event)
639+ err := handler.Handle(context.Background(), event)
640640
641641 assert.NoError(t, err)
642642 }
@@ -702,7 +702,7 @@ func TestAutoRouteHandler_Handle_MultipleDomains(t *testing.T) {
702702 },
703703 }
704704
705- err := handler.Handle(event)
705+ err := handler.Handle(context.Background(), event)
706706
707707 assert.NoError(t, err)
708708 }
@@ -368,7 +368,7 @@ func TestAutoRouteHandler_Handle_DisabledAutoRoute(t *testing.T) {
368 },368 },
369 }369 }
370 370
371- err := handler.Handle(event)371+ err := handler.Handle(context.Background(), event)
372 372
373 assert.NoError(t, err)373 assert.NoError(t, err)
374 }374 }
@@ -389,7 +389,7 @@ func TestAutoRouteHandler_Handle_InvalidPayload(t *testing.T) {
389 Data: "invalid payload type",389 Data: "invalid payload type",
390 }390 }
391 391
392- err := handler.Handle(event)392+ err := handler.Handle(context.Background(), event)
393 393
394 // Handler skips invalid payload, doesn't error394 // Handler skips invalid payload, doesn't error
395 assert.NoError(t, err)395 assert.NoError(t, err)
@@ -415,7 +415,7 @@ func TestAutoRouteHandler_Handle_EmptyManifest(t *testing.T) {
415 },415 },
416 }416 }
417 417
418- err := handler.Handle(event)418+ err := handler.Handle(context.Background(), event)
419 419
420 assert.NoError(t, err)420 assert.NoError(t, err)
421 }421 }
@@ -475,7 +475,7 @@ func TestAutoRouteHandler_Handle_CreatesNewRoute(t *testing.T) {
475 },475 },
476 }476 }
477 477
478- err := handler.Handle(event)478+ err := handler.Handle(context.Background(), event)
479 479
480 assert.NoError(t, err)480 assert.NoError(t, err)
481 }481 }
@@ -537,7 +537,7 @@ func TestAutoRouteHandler_Handle_UpdatesExistingRoute(t *testing.T) {
537 },537 },
538 }538 }
539 539
540- err := handler.Handle(event)540+ err := handler.Handle(context.Background(), event)
541 541
542 assert.NoError(t, err)542 assert.NoError(t, err)
543 }543 }
@@ -589,7 +589,7 @@ func TestAutoRouteHandler_Handle_NoUpdateIfSameImage(t *testing.T) {
589 },589 },
590 }590 }
591 591
592- err := handler.Handle(event)592+ err := handler.Handle(context.Background(), event)
593 593
594 assert.NoError(t, err)594 assert.NoError(t, err)
595 }595 }
@@ -636,7 +636,7 @@ func TestAutoRouteHandler_Handle_NoDomainLabel(t *testing.T) {
636 },636 },
637 }637 }
638 638
639- err := handler.Handle(event)639+ err := handler.Handle(context.Background(), event)
640 640
641 assert.NoError(t, err)641 assert.NoError(t, err)
642 }642 }
@@ -702,7 +702,7 @@ func TestAutoRouteHandler_Handle_MultipleDomains(t *testing.T) {
702 },702 },
703 }703 }
704 704
705- err := handler.Handle(event)705+ err := handler.Handle(context.Background(), event)
706 706
707 assert.NoError(t, err)707 assert.NoError(t, err)
708 }708 }
M internal/usecase/container/events.go +8 -8
@@ -28,8 +28,8 @@ func NewImagePushedHandler(ctx context.Context, containerSvc in.ContainerService
2828 }
2929
3030 // Handle handles an event.
31-func (h *ImagePushedHandler) Handle(event domain.Event) error {
32- ctx := zerowrap.CtxWithFields(h.ctx, map[string]any{
31+func (h *ImagePushedHandler) Handle(ctx context.Context, event domain.Event) error {
32+ ctx = zerowrap.CtxWithFields(ctx, map[string]any{
3333 zerowrap.FieldLayer: "usecase",
3434 zerowrap.FieldHandler: "ImagePushedHandler",
3535 zerowrap.FieldEvent: string(event.Type),
@@ -122,8 +122,8 @@ func NewConfigReloadHandler(ctx context.Context, containerSvc in.ContainerServic
122122 }
123123
124124 // Handle handles an event.
125-func (h *ConfigReloadHandler) Handle(event domain.Event) error {
126- ctx := zerowrap.CtxWithFields(h.ctx, map[string]any{
125+func (h *ConfigReloadHandler) Handle(ctx context.Context, event domain.Event) error {
126+ ctx = zerowrap.CtxWithFields(ctx, map[string]any{
127127 zerowrap.FieldLayer: "usecase",
128128 zerowrap.FieldHandler: "ConfigReloadHandler",
129129 zerowrap.FieldEvent: string(event.Type),
@@ -219,8 +219,8 @@ func NewManualReloadHandler(ctx context.Context, containerSvc in.ContainerServic
219219 // Handle handles an event.
220220 // It starts containers for configured routes that don't have a running container.
221221 // Running containers are NEVER restarted to ensure 100% uptime.
222-func (h *ManualReloadHandler) Handle(event domain.Event) error {
223- ctx := zerowrap.CtxWithFields(h.ctx, map[string]any{
222+func (h *ManualReloadHandler) Handle(ctx context.Context, event domain.Event) error {
223+ ctx = zerowrap.CtxWithFields(ctx, map[string]any{
224224 zerowrap.FieldLayer: "usecase",
225225 zerowrap.FieldHandler: "ManualReloadHandler",
226226 zerowrap.FieldEvent: string(event.Type),
@@ -302,8 +302,8 @@ func NewManualDeployHandler(ctx context.Context, containerSvc in.ContainerServic
302302 }
303303
304304 // Handle handles a manual deploy event for a specific route.
305-func (h *ManualDeployHandler) Handle(event domain.Event) error {
306- ctx := zerowrap.CtxWithFields(h.ctx, map[string]any{
305+func (h *ManualDeployHandler) Handle(ctx context.Context, event domain.Event) error {
306+ ctx = zerowrap.CtxWithFields(ctx, map[string]any{
307307 zerowrap.FieldLayer: "usecase",
308308 zerowrap.FieldHandler: "ManualDeployHandler",
309309 zerowrap.FieldEvent: string(event.Type),
@@ -28,8 +28,8 @@ func NewImagePushedHandler(ctx context.Context, containerSvc in.ContainerService
28 }28 }
29 29
30 // Handle handles an event.30 // Handle handles an event.
31-func (h *ImagePushedHandler) Handle(event domain.Event) error {31+func (h *ImagePushedHandler) Handle(ctx context.Context, event domain.Event) error {
32- ctx := zerowrap.CtxWithFields(h.ctx, map[string]any{32+ ctx = zerowrap.CtxWithFields(ctx, map[string]any{
33 zerowrap.FieldLayer: "usecase",33 zerowrap.FieldLayer: "usecase",
34 zerowrap.FieldHandler: "ImagePushedHandler",34 zerowrap.FieldHandler: "ImagePushedHandler",
35 zerowrap.FieldEvent: string(event.Type),35 zerowrap.FieldEvent: string(event.Type),
@@ -122,8 +122,8 @@ func NewConfigReloadHandler(ctx context.Context, containerSvc in.ContainerServic
122 }122 }
123 123
124 // Handle handles an event.124 // Handle handles an event.
125-func (h *ConfigReloadHandler) Handle(event domain.Event) error {125+func (h *ConfigReloadHandler) Handle(ctx context.Context, event domain.Event) error {
126- ctx := zerowrap.CtxWithFields(h.ctx, map[string]any{126+ ctx = zerowrap.CtxWithFields(ctx, map[string]any{
127 zerowrap.FieldLayer: "usecase",127 zerowrap.FieldLayer: "usecase",
128 zerowrap.FieldHandler: "ConfigReloadHandler",128 zerowrap.FieldHandler: "ConfigReloadHandler",
129 zerowrap.FieldEvent: string(event.Type),129 zerowrap.FieldEvent: string(event.Type),
@@ -219,8 +219,8 @@ func NewManualReloadHandler(ctx context.Context, containerSvc in.ContainerServic
219 // Handle handles an event.219 // Handle handles an event.
220 // It starts containers for configured routes that don't have a running container.220 // It starts containers for configured routes that don't have a running container.
221 // Running containers are NEVER restarted to ensure 100% uptime.221 // Running containers are NEVER restarted to ensure 100% uptime.
222-func (h *ManualReloadHandler) Handle(event domain.Event) error {222+func (h *ManualReloadHandler) Handle(ctx context.Context, event domain.Event) error {
223- ctx := zerowrap.CtxWithFields(h.ctx, map[string]any{223+ ctx = zerowrap.CtxWithFields(ctx, map[string]any{
224 zerowrap.FieldLayer: "usecase",224 zerowrap.FieldLayer: "usecase",
225 zerowrap.FieldHandler: "ManualReloadHandler",225 zerowrap.FieldHandler: "ManualReloadHandler",
226 zerowrap.FieldEvent: string(event.Type),226 zerowrap.FieldEvent: string(event.Type),
@@ -302,8 +302,8 @@ func NewManualDeployHandler(ctx context.Context, containerSvc in.ContainerServic
302 }302 }
303 303
304 // Handle handles a manual deploy event for a specific route.304 // Handle handles a manual deploy event for a specific route.
305-func (h *ManualDeployHandler) Handle(event domain.Event) error {305+func (h *ManualDeployHandler) Handle(ctx context.Context, event domain.Event) error {
306- ctx := zerowrap.CtxWithFields(h.ctx, map[string]any{306+ ctx = zerowrap.CtxWithFields(ctx, map[string]any{
307 zerowrap.FieldLayer: "usecase",307 zerowrap.FieldLayer: "usecase",
308 zerowrap.FieldHandler: "ManualDeployHandler",308 zerowrap.FieldHandler: "ManualDeployHandler",
309 zerowrap.FieldEvent: string(event.Type),309 zerowrap.FieldEvent: string(event.Type),
M internal/usecase/container/events_test.go +19 -19
@@ -63,7 +63,7 @@ func TestImagePushedHandler_Handle_DeploysMatchingRoutes(t *testing.T) {
6363 Tag: "latest",
6464 }
6565
66- err := handler.Handle(event)
66+ err := handler.Handle(context.Background(), event)
6767
6868 assert.NoError(t, err)
6969 }
@@ -89,7 +89,7 @@ func TestImagePushedHandler_Handle_NoMatchingRoutes(t *testing.T) {
8989 Tag: "latest",
9090 }
9191
92- err := handler.Handle(event)
92+ err := handler.Handle(context.Background(), event)
9393
9494 assert.NoError(t, err)
9595 }
@@ -107,7 +107,7 @@ func TestImagePushedHandler_Handle_EmptyImageName(t *testing.T) {
107107 Tag: "latest",
108108 }
109109
110- err := handler.Handle(event)
110+ err := handler.Handle(context.Background(), event)
111111
112112 assert.ErrorIs(t, err, domain.ErrInvalidImageFormat)
113113 }
@@ -137,7 +137,7 @@ func TestImagePushedHandler_Handle_DefaultTag(t *testing.T) {
137137 Tag: "", // Empty tag should default to "latest"
138138 }
139139
140- err := handler.Handle(event)
140+ err := handler.Handle(context.Background(), event)
141141
142142 assert.NoError(t, err)
143143 }
@@ -164,7 +164,7 @@ func TestImagePushedHandler_Handle_DeployError(t *testing.T) {
164164 }
165165
166166 // Handler logs error but doesn't fail
167- err := handler.Handle(event)
167+ err := handler.Handle(context.Background(), event)
168168
169169 assert.NoError(t, err)
170170 }
@@ -192,7 +192,7 @@ func TestImagePushedHandler_Handle_StripsRegistryDomain(t *testing.T) {
192192 Tag: "latest",
193193 }
194194
195- err := handler.Handle(event)
195+ err := handler.Handle(context.Background(), event)
196196
197197 assert.NoError(t, err)
198198 }
@@ -237,7 +237,7 @@ func TestConfigReloadHandler_Handle_DeploysNewRoutes(t *testing.T) {
237237 Type: domain.EventConfigReload,
238238 }
239239
240- err := handler.Handle(event)
240+ err := handler.Handle(context.Background(), event)
241241
242242 assert.NoError(t, err)
243243 }
@@ -273,7 +273,7 @@ func TestConfigReloadHandler_Handle_StopsRemovedRoutes(t *testing.T) {
273273 Type: domain.EventConfigReload,
274274 }
275275
276- err := handler.Handle(event)
276+ err := handler.Handle(context.Background(), event)
277277
278278 assert.NoError(t, err)
279279 }
@@ -313,7 +313,7 @@ func TestConfigReloadHandler_Handle_RedeploysChangedImage(t *testing.T) {
313313 Type: domain.EventConfigReload,
314314 }
315315
316- err := handler.Handle(event)
316+ err := handler.Handle(context.Background(), event)
317317
318318 assert.NoError(t, err)
319319 }
@@ -349,7 +349,7 @@ func TestConfigReloadHandler_Handle_NoChanges(t *testing.T) {
349349 Type: domain.EventConfigReload,
350350 }
351351
352- err := handler.Handle(event)
352+ err := handler.Handle(context.Background(), event)
353353
354354 assert.NoError(t, err)
355355 }
@@ -397,7 +397,7 @@ func TestManualReloadHandler_Handle_StartsOnlyMissingContainers(t *testing.T) {
397397 Type: domain.EventManualReload,
398398 }
399399
400- err := handler.Handle(event)
400+ err := handler.Handle(context.Background(), event)
401401
402402 assert.NoError(t, err)
403403 }
@@ -428,7 +428,7 @@ func TestManualReloadHandler_Handle_StartsMissingContainer(t *testing.T) {
428428 Type: domain.EventManualReload,
429429 }
430430
431- err := handler.Handle(event)
431+ err := handler.Handle(context.Background(), event)
432432
433433 assert.NoError(t, err)
434434 }
@@ -467,7 +467,7 @@ func TestManualReloadHandler_Handle_DeployErrors(t *testing.T) {
467467 Type: domain.EventManualReload,
468468 }
469469
470- err := handler.Handle(event)
470+ err := handler.Handle(context.Background(), event)
471471
472472 // Should return error indicating some failures
473473 assert.Error(t, err)
@@ -497,7 +497,7 @@ func TestManualReloadHandler_Handle_DoesNotRestartRunningContainers(t *testing.T
497497 Type: domain.EventManualReload,
498498 }
499499
500- err := handler.Handle(event)
500+ err := handler.Handle(context.Background(), event)
501501
502502 assert.NoError(t, err)
503503 }
@@ -539,7 +539,7 @@ func TestManualDeployHandler_Handle_DeploysSpecificRoute(t *testing.T) {
539539 Data: &domain.ManualDeployPayload{Domain: "app1.example.com"},
540540 }
541541
542- err := handler.Handle(event)
542+ err := handler.Handle(context.Background(), event)
543543
544544 assert.NoError(t, err)
545545 }
@@ -561,7 +561,7 @@ func TestManualDeployHandler_Handle_RouteNotFound(t *testing.T) {
561561 Data: &domain.ManualDeployPayload{Domain: "unknown.example.com"},
562562 }
563563
564- err := handler.Handle(event)
564+ err := handler.Handle(context.Background(), event)
565565
566566 assert.Error(t, err)
567567 assert.Contains(t, err.Error(), "route not found")
@@ -580,7 +580,7 @@ func TestManualDeployHandler_Handle_InvalidPayload(t *testing.T) {
580580 Data: nil,
581581 }
582582
583- err := handler.Handle(event)
583+ err := handler.Handle(context.Background(), event)
584584
585585 assert.Error(t, err)
586586 assert.Contains(t, err.Error(), "invalid manual deploy payload")
@@ -599,7 +599,7 @@ func TestManualDeployHandler_Handle_EmptyDomain(t *testing.T) {
599599 Data: &domain.ManualDeployPayload{Domain: ""},
600600 }
601601
602- err := handler.Handle(event)
602+ err := handler.Handle(context.Background(), event)
603603
604604 assert.Error(t, err)
605605 assert.Contains(t, err.Error(), "invalid manual deploy payload")
@@ -623,7 +623,7 @@ func TestManualDeployHandler_Handle_DeployError(t *testing.T) {
623623 Data: &domain.ManualDeployPayload{Domain: "app.example.com"},
624624 }
625625
626- err := handler.Handle(event)
626+ err := handler.Handle(context.Background(), event)
627627
628628 assert.Error(t, err)
629629 assert.Contains(t, err.Error(), "failed to deploy")
@@ -63,7 +63,7 @@ func TestImagePushedHandler_Handle_DeploysMatchingRoutes(t *testing.T) {
63 Tag: "latest",63 Tag: "latest",
64 }64 }
65 65
66- err := handler.Handle(event)66+ err := handler.Handle(context.Background(), event)
67 67
68 assert.NoError(t, err)68 assert.NoError(t, err)
69 }69 }
@@ -89,7 +89,7 @@ func TestImagePushedHandler_Handle_NoMatchingRoutes(t *testing.T) {
89 Tag: "latest",89 Tag: "latest",
90 }90 }
91 91
92- err := handler.Handle(event)92+ err := handler.Handle(context.Background(), event)
93 93
94 assert.NoError(t, err)94 assert.NoError(t, err)
95 }95 }
@@ -107,7 +107,7 @@ func TestImagePushedHandler_Handle_EmptyImageName(t *testing.T) {
107 Tag: "latest",107 Tag: "latest",
108 }108 }
109 109
110- err := handler.Handle(event)110+ err := handler.Handle(context.Background(), event)
111 111
112 assert.ErrorIs(t, err, domain.ErrInvalidImageFormat)112 assert.ErrorIs(t, err, domain.ErrInvalidImageFormat)
113 }113 }
@@ -137,7 +137,7 @@ func TestImagePushedHandler_Handle_DefaultTag(t *testing.T) {
137 Tag: "", // Empty tag should default to "latest"137 Tag: "", // Empty tag should default to "latest"
138 }138 }
139 139
140- err := handler.Handle(event)140+ err := handler.Handle(context.Background(), event)
141 141
142 assert.NoError(t, err)142 assert.NoError(t, err)
143 }143 }
@@ -164,7 +164,7 @@ func TestImagePushedHandler_Handle_DeployError(t *testing.T) {
164 }164 }
165 165
166 // Handler logs error but doesn't fail166 // Handler logs error but doesn't fail
167- err := handler.Handle(event)167+ err := handler.Handle(context.Background(), event)
168 168
169 assert.NoError(t, err)169 assert.NoError(t, err)
170 }170 }
@@ -192,7 +192,7 @@ func TestImagePushedHandler_Handle_StripsRegistryDomain(t *testing.T) {
192 Tag: "latest",192 Tag: "latest",
193 }193 }
194 194
195- err := handler.Handle(event)195+ err := handler.Handle(context.Background(), event)
196 196
197 assert.NoError(t, err)197 assert.NoError(t, err)
198 }198 }
@@ -237,7 +237,7 @@ func TestConfigReloadHandler_Handle_DeploysNewRoutes(t *testing.T) {
237 Type: domain.EventConfigReload,237 Type: domain.EventConfigReload,
238 }238 }
239 239
240- err := handler.Handle(event)240+ err := handler.Handle(context.Background(), event)
241 241
242 assert.NoError(t, err)242 assert.NoError(t, err)
243 }243 }
@@ -273,7 +273,7 @@ func TestConfigReloadHandler_Handle_StopsRemovedRoutes(t *testing.T) {
273 Type: domain.EventConfigReload,273 Type: domain.EventConfigReload,
274 }274 }
275 275
276- err := handler.Handle(event)276+ err := handler.Handle(context.Background(), event)
277 277
278 assert.NoError(t, err)278 assert.NoError(t, err)
279 }279 }
@@ -313,7 +313,7 @@ func TestConfigReloadHandler_Handle_RedeploysChangedImage(t *testing.T) {
313 Type: domain.EventConfigReload,313 Type: domain.EventConfigReload,
314 }314 }
315 315
316- err := handler.Handle(event)316+ err := handler.Handle(context.Background(), event)
317 317
318 assert.NoError(t, err)318 assert.NoError(t, err)
319 }319 }
@@ -349,7 +349,7 @@ func TestConfigReloadHandler_Handle_NoChanges(t *testing.T) {
349 Type: domain.EventConfigReload,349 Type: domain.EventConfigReload,
350 }350 }
351 351
352- err := handler.Handle(event)352+ err := handler.Handle(context.Background(), event)
353 353
354 assert.NoError(t, err)354 assert.NoError(t, err)
355 }355 }
@@ -397,7 +397,7 @@ func TestManualReloadHandler_Handle_StartsOnlyMissingContainers(t *testing.T) {
397 Type: domain.EventManualReload,397 Type: domain.EventManualReload,
398 }398 }
399 399
400- err := handler.Handle(event)400+ err := handler.Handle(context.Background(), event)
401 401
402 assert.NoError(t, err)402 assert.NoError(t, err)
403 }403 }
@@ -428,7 +428,7 @@ func TestManualReloadHandler_Handle_StartsMissingContainer(t *testing.T) {
428 Type: domain.EventManualReload,428 Type: domain.EventManualReload,
429 }429 }
430 430
431- err := handler.Handle(event)431+ err := handler.Handle(context.Background(), event)
432 432
433 assert.NoError(t, err)433 assert.NoError(t, err)
434 }434 }
@@ -467,7 +467,7 @@ func TestManualReloadHandler_Handle_DeployErrors(t *testing.T) {
467 Type: domain.EventManualReload,467 Type: domain.EventManualReload,
468 }468 }
469 469
470- err := handler.Handle(event)470+ err := handler.Handle(context.Background(), event)
471 471
472 // Should return error indicating some failures472 // Should return error indicating some failures
473 assert.Error(t, err)473 assert.Error(t, err)
@@ -497,7 +497,7 @@ func TestManualReloadHandler_Handle_DoesNotRestartRunningContainers(t *testing.T
497 Type: domain.EventManualReload,497 Type: domain.EventManualReload,
498 }498 }
499 499
500- err := handler.Handle(event)500+ err := handler.Handle(context.Background(), event)
501 501
502 assert.NoError(t, err)502 assert.NoError(t, err)
503 }503 }
@@ -539,7 +539,7 @@ func TestManualDeployHandler_Handle_DeploysSpecificRoute(t *testing.T) {
539 Data: &domain.ManualDeployPayload{Domain: "app1.example.com"},539 Data: &domain.ManualDeployPayload{Domain: "app1.example.com"},
540 }540 }
541 541
542- err := handler.Handle(event)542+ err := handler.Handle(context.Background(), event)
543 543
544 assert.NoError(t, err)544 assert.NoError(t, err)
545 }545 }
@@ -561,7 +561,7 @@ func TestManualDeployHandler_Handle_RouteNotFound(t *testing.T) {
561 Data: &domain.ManualDeployPayload{Domain: "unknown.example.com"},561 Data: &domain.ManualDeployPayload{Domain: "unknown.example.com"},
562 }562 }
563 563
564- err := handler.Handle(event)564+ err := handler.Handle(context.Background(), event)
565 565
566 assert.Error(t, err)566 assert.Error(t, err)
567 assert.Contains(t, err.Error(), "route not found")567 assert.Contains(t, err.Error(), "route not found")
@@ -580,7 +580,7 @@ func TestManualDeployHandler_Handle_InvalidPayload(t *testing.T) {
580 Data: nil,580 Data: nil,
581 }581 }
582 582
583- err := handler.Handle(event)583+ err := handler.Handle(context.Background(), event)
584 584
585 assert.Error(t, err)585 assert.Error(t, err)
586 assert.Contains(t, err.Error(), "invalid manual deploy payload")586 assert.Contains(t, err.Error(), "invalid manual deploy payload")
@@ -599,7 +599,7 @@ func TestManualDeployHandler_Handle_EmptyDomain(t *testing.T) {
599 Data: &domain.ManualDeployPayload{Domain: ""},599 Data: &domain.ManualDeployPayload{Domain: ""},
600 }600 }
601 601
602- err := handler.Handle(event)602+ err := handler.Handle(context.Background(), event)
603 603
604 assert.Error(t, err)604 assert.Error(t, err)
605 assert.Contains(t, err.Error(), "invalid manual deploy payload")605 assert.Contains(t, err.Error(), "invalid manual deploy payload")
@@ -623,7 +623,7 @@ func TestManualDeployHandler_Handle_DeployError(t *testing.T) {
623 Data: &domain.ManualDeployPayload{Domain: "app.example.com"},623 Data: &domain.ManualDeployPayload{Domain: "app.example.com"},
624 }624 }
625 625
626- err := handler.Handle(event)626+ err := handler.Handle(context.Background(), event)
627 627
628 assert.Error(t, err)628 assert.Error(t, err)
629 assert.Contains(t, err.Error(), "failed to deploy")629 assert.Contains(t, err.Error(), "failed to deploy")
M internal/usecase/proxy/events.go +4 -4
@@ -28,8 +28,8 @@ func NewContainerDeployedHandler(ctx context.Context, invalidator TargetInvalida
2828 }
2929
3030 // Handle handles a container.deployed event by invalidating the proxy cache.
31-func (h *ContainerDeployedHandler) Handle(event domain.Event) error {
32- ctx := zerowrap.CtxWithFields(h.ctx, map[string]any{
31+func (h *ContainerDeployedHandler) Handle(ctx context.Context, event domain.Event) error {
32+ ctx = zerowrap.CtxWithFields(ctx, map[string]any{
3333 zerowrap.FieldLayer: "usecase",
3434 zerowrap.FieldHandler: "ContainerDeployedHandler",
3535 zerowrap.FieldEvent: string(event.Type),
@@ -84,8 +84,8 @@ func NewConfigReloadProxyHandler(ctx context.Context, refresher TargetRefresher)
8484 }
8585
8686 // Handle clears all cached proxy targets so they are re-resolved from current state.
87-func (h *ConfigReloadProxyHandler) Handle(event domain.Event) error {
88- ctx := zerowrap.CtxWithFields(h.ctx, map[string]any{
87+func (h *ConfigReloadProxyHandler) Handle(ctx context.Context, event domain.Event) error {
88+ ctx = zerowrap.CtxWithFields(ctx, map[string]any{
8989 zerowrap.FieldLayer: "usecase",
9090 zerowrap.FieldHandler: "ConfigReloadProxyHandler",
9191 zerowrap.FieldEvent: string(event.Type),
@@ -28,8 +28,8 @@ func NewContainerDeployedHandler(ctx context.Context, invalidator TargetInvalida
28 }28 }
29 29
30 // Handle handles a container.deployed event by invalidating the proxy cache.30 // Handle handles a container.deployed event by invalidating the proxy cache.
31-func (h *ContainerDeployedHandler) Handle(event domain.Event) error {31+func (h *ContainerDeployedHandler) Handle(ctx context.Context, event domain.Event) error {
32- ctx := zerowrap.CtxWithFields(h.ctx, map[string]any{32+ ctx = zerowrap.CtxWithFields(ctx, map[string]any{
33 zerowrap.FieldLayer: "usecase",33 zerowrap.FieldLayer: "usecase",
34 zerowrap.FieldHandler: "ContainerDeployedHandler",34 zerowrap.FieldHandler: "ContainerDeployedHandler",
35 zerowrap.FieldEvent: string(event.Type),35 zerowrap.FieldEvent: string(event.Type),
@@ -84,8 +84,8 @@ func NewConfigReloadProxyHandler(ctx context.Context, refresher TargetRefresher)
84 }84 }
85 85
86 // Handle clears all cached proxy targets so they are re-resolved from current state.86 // Handle clears all cached proxy targets so they are re-resolved from current state.
87-func (h *ConfigReloadProxyHandler) Handle(event domain.Event) error {87+func (h *ConfigReloadProxyHandler) Handle(ctx context.Context, event domain.Event) error {
88- ctx := zerowrap.CtxWithFields(h.ctx, map[string]any{88+ ctx = zerowrap.CtxWithFields(ctx, map[string]any{
89 zerowrap.FieldLayer: "usecase",89 zerowrap.FieldLayer: "usecase",
90 zerowrap.FieldHandler: "ConfigReloadProxyHandler",90 zerowrap.FieldHandler: "ConfigReloadProxyHandler",
91 zerowrap.FieldEvent: string(event.Type),91 zerowrap.FieldEvent: string(event.Type),
M internal/usecase/proxy/service_test.go +2 -2
@@ -361,7 +361,7 @@ func TestContainerDeployedHandler_Handle_InvalidatesCache(t *testing.T) {
361361 },
362362 }
363363
364- err := handler.Handle(event)
364+ err := handler.Handle(context.Background(), event)
365365
366366 assert.NoError(t, err)
367367
@@ -393,7 +393,7 @@ func TestContainerDeployedHandler_Handle_NoDomain(t *testing.T) {
393393 }
394394
395395 // Should not error, just skip
396- err := handler.Handle(event)
396+ err := handler.Handle(context.Background(), event)
397397 assert.NoError(t, err)
398398 }
399399
@@ -361,7 +361,7 @@ func TestContainerDeployedHandler_Handle_InvalidatesCache(t *testing.T) {
361 },361 },
362 }362 }
363 363
364- err := handler.Handle(event)364+ err := handler.Handle(context.Background(), event)
365 365
366 assert.NoError(t, err)366 assert.NoError(t, err)
367 367
@@ -393,7 +393,7 @@ func TestContainerDeployedHandler_Handle_NoDomain(t *testing.T) {
393 }393 }
394 394
395 // Should not error, just skip395 // Should not error, just skip
396- err := handler.Handle(event)396+ err := handler.Handle(context.Background(), event)
397 assert.NoError(t, err)397 assert.NoError(t, err)
398 }398 }
399 399

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close