Skip to content

Commit abe1f56

Browse files
authored
feat: add OnClose hooks in Client instance (#1054)
1 parent 18a2f5e commit abe1f56

File tree

2 files changed

+58
-0
lines changed

2 files changed

+58
-0
lines changed

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

@@ -2381,6 +2398,15 @@ func (c *Client) onInvalidHooks(req *Request, err error) {
23812398
}
23822399
}
23832400

2401+
// Helper to run closeHooks hooks.
2402+
func (c *Client) onCloseHooks() {
2403+
c.lock.RLock()
2404+
defer c.lock.RUnlock()
2405+
for _, h := range c.closeHooks {
2406+
h()
2407+
}
2408+
}
2409+
23842410
func (c *Client) debugf(format string, v ...any) {
23852411
if c.IsDebug() {
23862412
c.Logger().Debugf(format, v...)

client_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1524,3 +1524,35 @@ func TestClientCircuitBreaker(t *testing.T) {
15241524
assertError(t, err)
15251525
assertEqual(t, uint32(1), c.circuitBreaker.failureCount.Load())
15261526
}
1527+
1528+
func TestClientOnClose(t *testing.T) {
1529+
var hookExecuted bool
1530+
1531+
c := dcnl()
1532+
c.OnClose(func() {
1533+
hookExecuted = true
1534+
})
1535+
1536+
err := c.Close()
1537+
assertNil(t, err)
1538+
assertEqual(t, true, hookExecuted)
1539+
}
1540+
1541+
func TestClientOnCloseMultipleHooks(t *testing.T) {
1542+
var executionOrder []string
1543+
1544+
c := dcnl()
1545+
c.OnClose(func() {
1546+
executionOrder = append(executionOrder, "first")
1547+
})
1548+
c.OnClose(func() {
1549+
executionOrder = append(executionOrder, "second")
1550+
})
1551+
c.OnClose(func() {
1552+
executionOrder = append(executionOrder, "third")
1553+
})
1554+
1555+
err := c.Close()
1556+
assertNil(t, err)
1557+
assertEqual(t, []string{"first", "second", "third"}, executionOrder)
1558+
}

0 commit comments

Comments
 (0)