Skip to content

Commit 201e7fb

Browse files
committed
Add close hooks
1 parent 66256ef commit 201e7fb

2 files changed

Lines changed: 58 additions & 0 deletions

File tree

client.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ type (
9595
// SuccessHook type is for reacting to request success
9696
SuccessHook func(*Client, *Response)
9797

98+
// CloseHook type is for reacting to client closing
99+
CloseHook func()
100+
98101
// RequestFunc type is for extended manipulation of the Request instance
99102
RequestFunc func(*Request) *Request
100103

@@ -215,6 +218,7 @@ type Client struct {
215218
invalidHooks []ErrorHook
216219
panicHooks []ErrorHook
217220
successHooks []SuccessHook
221+
closeHooks []CloseHook
218222
contentTypeEncoders map[string]ContentTypeEncoder
219223
contentTypeDecoders map[string]ContentTypeDecoder
220224
contentDecompresserKeys []string
@@ -838,6 +842,15 @@ func (c *Client) OnPanic(h ErrorHook) *Client {
838842
return c
839843
}
840844

845+
// OnClose method adds a callback that will be run whenever the client is closed.
846+
// The hooks are executed in the order they were registered.
847+
func (c *Client) OnClose(h CloseHook) *Client {
848+
c.lock.Lock()
849+
defer c.lock.Unlock()
850+
c.closeHooks = append(c.closeHooks, h)
851+
return c
852+
}
853+
841854
// ContentTypeEncoders method returns all the registered content type encoders.
842855
func (c *Client) ContentTypeEncoders() map[string]ContentTypeEncoder {
843856
c.lock.RLock()
@@ -2221,10 +2234,14 @@ func (c *Client) Clone(ctx context.Context) *Client {
22212234

22222235
// Close method performs cleanup and closure activities on the client instance
22232236
func (c *Client) Close() error {
2237+
// Execute close hooks first
2238+
c.onCloseHooks()
2239+
22242240
if c.LoadBalancer() != nil {
22252241
silently(c.LoadBalancer().Close())
22262242
}
22272243
close(c.certWatcherStopChan)
2244+
22282245
return nil
22292246
}
22302247

@@ -2377,6 +2394,15 @@ func (c *Client) onInvalidHooks(req *Request, err error) {
23772394
}
23782395
}
23792396

2397+
// Helper to run closeHooks hooks.
2398+
func (c *Client) onCloseHooks() {
2399+
c.lock.RLock()
2400+
defer c.lock.RUnlock()
2401+
for _, h := range c.closeHooks {
2402+
h()
2403+
}
2404+
}
2405+
23802406
func (c *Client) debugf(format string, v ...any) {
23812407
if c.IsDebug() {
23822408
c.Logger().Debugf(format, v...)

client_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,3 +1515,35 @@ func TestClientCircuitBreaker(t *testing.T) {
15151515
assertError(t, err)
15161516
assertEqual(t, uint32(1), c.circuitBreaker.failureCount.Load())
15171517
}
1518+
1519+
func TestClientOnClose(t *testing.T) {
1520+
var hookExecuted bool
1521+
1522+
c := dcnl()
1523+
c.OnClose(func() {
1524+
hookExecuted = true
1525+
})
1526+
1527+
err := c.Close()
1528+
assertNil(t, err)
1529+
assertEqual(t, true, hookExecuted)
1530+
}
1531+
1532+
func TestClientOnCloseMultipleHooks(t *testing.T) {
1533+
var executionOrder []string
1534+
1535+
c := dcnl()
1536+
c.OnClose(func() {
1537+
executionOrder = append(executionOrder, "first")
1538+
})
1539+
c.OnClose(func() {
1540+
executionOrder = append(executionOrder, "second")
1541+
})
1542+
c.OnClose(func() {
1543+
executionOrder = append(executionOrder, "third")
1544+
})
1545+
1546+
err := c.Close()
1547+
assertNil(t, err)
1548+
assertEqual(t, []string{"first", "second", "third"}, executionOrder)
1549+
}

0 commit comments

Comments
 (0)