Skip to content

Commit b3c3ac6

Browse files
authored
feat(client): pass isSuccess to ClientRetryPlugin onRetry returned callback (#389)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Enhanced retry functionality now executes a callback after each retry attempt, clearly indicating success or failure. This improvement provides more robust handling during repeated operations. - **Documentation** - Updated documentation to reflect the new retry behavior and callback structure. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 8ec326d commit b3c3ac6

3 files changed

Lines changed: 35 additions & 16 deletions

File tree

apps/content/docs/plugins/client-retry.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,13 @@ const planets = await client.planet.list({ limit: 10 }, {
5454
retry: 3, // Maximum retry attempts
5555
retryDelay: 2000, // Delay between retries in ms
5656
shouldRetry: options => true, // Determines whether to retry based on the error
57-
onRetry: (options) => {}, // Hook executed on each retry
57+
onRetry: (options) => {
58+
// Hook executed on each retry
59+
60+
return (isSuccess) => {
61+
// Execute after the retry is complete
62+
}
63+
},
5864
}
5965
})
6066
```

packages/client/src/plugins/retry.test.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,21 @@ describe('clientRetryPlugin', () => {
122122
})
123123

124124
it('onRetry', async () => {
125-
handlerFn.mockRejectedValue(new Error('fail'))
125+
let count = 0
126+
handlerFn.mockImplementation(() => {
127+
count++
128+
129+
if (count === 4) {
130+
return 'success'
131+
}
132+
133+
throw new Error('fail')
134+
})
126135

127136
const clean = vi.fn()
128137
const onRetry = vi.fn(() => clean)
129138

130-
await expect(client('hello', { context: { retry: 3, retryDelay: 0, onRetry } })).rejects.toThrow('Internal server error')
139+
await expect(client('hello', { context: { retry: 3, retryDelay: 0, onRetry } })).resolves.toEqual('success')
131140

132141
expect(handlerFn).toHaveBeenCalledTimes(4)
133142

@@ -164,6 +173,9 @@ describe('clientRetryPlugin', () => {
164173
)
165174

166175
expect(clean).toHaveBeenCalledTimes(3)
176+
expect(clean).toHaveBeenNthCalledWith(1, false)
177+
expect(clean).toHaveBeenNthCalledWith(2, false)
178+
expect(clean).toHaveBeenNthCalledWith(3, true)
167179
})
168180

169181
it('should not retry if signal aborted', async () => {

packages/client/src/plugins/retry.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export interface ClientRetryPluginContext {
3636
/**
3737
* The hook called when retrying, and return the unsubscribe function.
3838
*/
39-
onRetry?: (options: ClientRetryPluginAttemptOptions<ClientRetryPluginContext>) => void | (() => void)
39+
onRetry?: (options: ClientRetryPluginAttemptOptions<ClientRetryPluginContext>) => void | ((isSuccess: boolean) => void)
4040
}
4141

4242
export class ClientRetryPluginInvalidEventIteratorRetryResponse extends Error { }
@@ -77,24 +77,24 @@ export class ClientRetryPlugin<T extends ClientRetryPluginContext> implements St
7777

7878
let lastEventId = interceptorOptions.lastEventId
7979
let lastEventRetry: undefined | number
80-
let unsubscribe: void | (() => void)
80+
let callback: void | ((isSuccess: boolean) => void)
8181
let attemptIndex = 0
8282

83-
const next = async (initial?: { error: unknown }) => {
84-
let current = initial
83+
const next = async (initialError?: { error: unknown }) => {
84+
let currentError = initialError
8585

8686
while (true) {
8787
const updatedInterceptorOptions = { ...interceptorOptions, lastEventId }
8888

89-
if (current) {
89+
if (currentError) {
9090
if (attemptIndex >= maxAttempts) {
91-
throw current.error
91+
throw currentError.error
9292
}
9393

9494
const attemptOptions: ClientRetryPluginAttemptOptions<ClientRetryPluginContext> = {
9595
...updatedInterceptorOptions,
9696
attemptIndex,
97-
error: current.error,
97+
error: currentError.error,
9898
lastEventRetry,
9999
}
100100

@@ -104,10 +104,10 @@ export class ClientRetryPlugin<T extends ClientRetryPluginContext> implements St
104104
)
105105

106106
if (!shouldRetryBool) {
107-
throw current.error
107+
throw currentError.error
108108
}
109109

110-
unsubscribe = onRetry?.(attemptOptions)
110+
callback = onRetry?.(attemptOptions)
111111

112112
const retryDelayMs = await value(retryDelay, attemptOptions)
113113

@@ -117,18 +117,19 @@ export class ClientRetryPlugin<T extends ClientRetryPluginContext> implements St
117117
}
118118

119119
try {
120+
currentError = undefined
120121
return await interceptorOptions.next(updatedInterceptorOptions)
121122
}
122123
catch (error) {
124+
currentError = { error }
125+
123126
if (updatedInterceptorOptions.signal?.aborted === true) {
124127
throw error
125128
}
126-
127-
current = { error }
128129
}
129130
finally {
130-
unsubscribe?.()
131-
unsubscribe = undefined
131+
callback?.(!currentError)
132+
callback = undefined
132133
}
133134
}
134135
}

0 commit comments

Comments
 (0)