Summary
The uploadProof$() method in DiaBackendAssetUploadingService uses an unbounded retryWhen with exponential backoff but no maximum retry limit and no error classification. Every error — including permanent, non-retryable errors like HTTP 403, 413, or server-side validation errors — triggers an infinite retry loop.
Impact
- Battery and network drain: On mobile devices, infinite retries waste battery and bandwidth indefinitely
- Upload queue deadlock: Because
uploadTaskWorker$() uses concatMap, an infinitely-retrying proof blocks all subsequent proofs from uploading — a single failure deadlocks the entire pipeline
- No user feedback: No logging, telemetry, or notification when retries are occurring
- Deprecated API:
retryWhen is deprecated in RxJS 7 and will be removed in a future version
Affected File
src/app/shared/dia-backend/asset/uploading/dia-backend-asset-uploading.service.ts — lines 152-158 (the retryWhen block within uploadProof$())
Related Bug: lodash.reject shadowing Promise reject
In src/app/shared/dia-backend/auth/dia-backend-auth.service.ts (line 440), the reject identifier used inside getToken() refers to lodash-es's reject() function (imported on line 5), NOT the Promise reject callback. When the token is empty, this calls lodash.reject(new Error(...)) which is a no-op, causing the Promise to hang forever. This silently deadlocks all 30+ authenticated API paths and compounds the upload retry issue — an upload hanging due to missing auth enters the infinite retry loop.
Suggested Implementation
Replace unbounded retryWhen with the modern retry() operator:
retry({
count: 5, // Max retries
delay: (error, retryCount) => {
// Don't retry non-retryable HTTP errors
if (error instanceof HttpErrorResponse) {
const status = error.status;
if ([401, 403, 413, 422].includes(status)) {
return throwError(() => error);
}
}
// Exponential backoff with jitter, capped at 60s
const delay = Math.min(1000 * Math.pow(2, retryCount - 1) + Math.random() * 500, 60000);
console.warn(`Upload retry ${retryCount}/5, delay: ${delay}ms`, error);
return timer(delay);
},
})
Also fix the getToken() bug by:
- Removing
reject from the lodash-es import on line 5
- Using the Promise
reject parameter properly in the new Promise<string>((resolve, reject) => {...}) constructor
Generated by Health Monitor with Omni
Summary
The
uploadProof$()method inDiaBackendAssetUploadingServiceuses an unboundedretryWhenwith exponential backoff but no maximum retry limit and no error classification. Every error — including permanent, non-retryable errors like HTTP 403, 413, or server-side validation errors — triggers an infinite retry loop.Impact
uploadTaskWorker$()usesconcatMap, an infinitely-retrying proof blocks all subsequent proofs from uploading — a single failure deadlocks the entire pipelineretryWhenis deprecated in RxJS 7 and will be removed in a future versionAffected File
src/app/shared/dia-backend/asset/uploading/dia-backend-asset-uploading.service.ts— lines 152-158 (theretryWhenblock withinuploadProof$())Related Bug:
lodash.rejectshadowing Promise rejectIn
src/app/shared/dia-backend/auth/dia-backend-auth.service.ts(line 440), therejectidentifier used insidegetToken()refers tolodash-es'sreject()function (imported on line 5), NOT the Promiserejectcallback. When the token is empty, this callslodash.reject(new Error(...))which is a no-op, causing the Promise to hang forever. This silently deadlocks all 30+ authenticated API paths and compounds the upload retry issue — an upload hanging due to missing auth enters the infinite retry loop.Suggested Implementation
Replace unbounded
retryWhenwith the modernretry()operator:Also fix the
getToken()bug by:rejectfrom thelodash-esimport on line 5rejectparameter properly in thenew Promise<string>((resolve, reject) => {...})constructorGenerated by Health Monitor with Omni