Skip to content

[Feature][High] Fix concurrency bugs: prefetch race condition, transaction observable leak, media store crash #3394

@numbers-official

Description

@numbers-official

Summary

Three high-priority reliability issues involving concurrency, observable management, and error recovery in core shared services.


1. Race Condition in Prefetching Service

File: src/app/shared/dia-backend/asset/prefetching/dia-backend-asset-prefetching.service.ts
Lines: 35-46

Promise.all() runs concurrent downloads that mutate a shared currentCount variable. Concurrent callback executions can cause out-of-order or skipped progress counts.

await Promise.all(
  diaBackendAssets.map(async diaBackendAsset => {
    // ... download logic ...
    currentCount += 1;  // Race condition: concurrent writes
    onStored(currentCount, totalCount);
  })
);

Fix: Use sequential for...of processing or an atomic counter pattern to ensure deterministic progress reporting.


2. Observable Memory Leak in Transaction Repository

File: src/app/shared/dia-backend/transaction/dia-backend-transaction-repository.service.ts
Lines: 55-90

The downloadExpired$ observable chain combines multiple sources and chains concatMap() operations without any catchError() operator. Failed transaction downloads can leave hanging subscriptions and partial state in parent components.

Fix: Add catchError() at the end of the observable chain with proper fallback behavior. Log errors to observability system.


3. Missing Error Recovery in Media Store

File: src/app/shared/media/media-store/media-store.service.ts
Lines: 265-273

getUrl() has no error handling for Capacitor.convertFileSrc() failures or invalid file system data. Missing/corrupted media silently breaks the display pipeline.

async getUrl(index: string, mimeType: MimeType) {
  if (Capacitor.isNativePlatform()) {
    await this.fixIncorrectExtension(index, mimeType);
    return Capacitor.convertFileSrc(await this.getUri(index));  // No try-catch
  }
  return URL.createObjectURL(
    await base64ToBlob(await this.readWithFileSystem(index), mimeType)  // No error handling
  );
}

Fix: Wrap in try-catch, return placeholder on failure, implement retry for transient file system errors.

Expected Impact

  • Accurate progress reporting during prefetch operations
  • Prevent memory accumulation from leaked observables
  • Graceful media display fallback instead of silent crashes

Generated by Heart Beat with Omni

Metadata

Metadata

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions