Skip to content

Commit 05918ca

Browse files
Fix memory leak by storing and clearing retry timer references
1 parent d6a187e commit 05918ca

4 files changed

Lines changed: 26 additions & 5 deletions

File tree

packages/upload-media/src/store/actions.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,11 @@ export function cancelItem( id: QueueItemId, error: Error, silent = false ) {
218218

219219
logCancel( id, item.file.name, error );
220220

221+
// Clear any pending retry timer to prevent memory leaks.
222+
if ( item.retryTimerId ) {
223+
clearTimeout( item.retryTimerId );
224+
}
225+
221226
item.abortController?.abort();
222227

223228
// Cancel any ongoing vips operations for this item.
@@ -270,6 +275,11 @@ export function retryItem( id: QueueItemId ) {
270275
previousError: item.error.message,
271276
} );
272277

278+
// Clear any pending retry timer to prevent duplicate retries.
279+
if ( item.retryTimerId ) {
280+
clearTimeout( item.retryTimerId );
281+
}
282+
273283
dispatch< RetryItemAction >( {
274284
type: Type.RetryItem,
275285
id,
@@ -318,18 +328,19 @@ export function scheduleRetry( id: QueueItemId, error: Error ) {
318328

319329
logRetryScheduled( id, item.file.name, nextRetryCount, delay );
320330

331+
// Schedule the retry execution and capture timer ID for cleanup.
332+
const retryTimerId = setTimeout( () => {
333+
dispatch.executeRetry( id );
334+
}, delay );
335+
321336
dispatch< ScheduleRetryAction >( {
322337
type: Type.ScheduleRetry,
323338
id,
324339
error,
325340
retryCount: currentRetryCount,
326341
nextRetryTimestamp: Date.now() + delay,
342+
retryTimerId,
327343
} );
328-
329-
// Schedule the retry execution
330-
setTimeout( () => {
331-
dispatch.executeRetry( id );
332-
}, delay );
333344
};
334345
}
335346

packages/upload-media/src/store/private-actions.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,11 @@ export function removeItem( id: QueueItemId ) {
557557

558558
logQueueRemove( id, item.file.name );
559559

560+
// Clear any pending retry timer to prevent memory leaks.
561+
if ( item.retryTimerId ) {
562+
clearTimeout( item.retryTimerId );
563+
}
564+
560565
dispatch( {
561566
type: Type.Remove,
562567
id,

packages/upload-media/src/store/reducer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ function reducer(
149149
status: ItemStatus.Processing,
150150
error: undefined,
151151
retryCount: ( item.retryCount ?? 0 ) + 1,
152+
retryTimerId: undefined,
152153
}
153154
: item
154155
),
@@ -167,6 +168,7 @@ function reducer(
167168
retryCount: action.retryCount,
168169
nextRetryTimestamp:
169170
action.nextRetryTimestamp,
171+
retryTimerId: action.retryTimerId,
170172
}
171173
: item
172174
),

packages/upload-media/src/store/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ export interface QueueItem {
3030
nextRetryTimestamp?: number;
3131
/** The operation that failed and needs to be retried. */
3232
failedOperation?: Operation;
33+
/** Timer ID for scheduled retry, used to clear the timer on cancellation. */
34+
retryTimerId?: ReturnType< typeof setTimeout >;
3335
}
3436

3537
export interface State {
@@ -99,6 +101,7 @@ export type ScheduleRetryAction = Action<
99101
error: Error;
100102
retryCount: number;
101103
nextRetryTimestamp: number;
104+
retryTimerId: ReturnType< typeof setTimeout >;
102105
}
103106
>;
104107
export type PauseItemAction = Action< Type.PauseItem, { id: QueueItemId } >;

0 commit comments

Comments
 (0)