# Data sync does not block UI thread

- **Pattern:** `ab-001880` (`mobile-offline-storage.offline-behavior.non-blocking-sync`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001880
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001880)

## Why it matters

Running sync operations synchronously on the JavaScript thread blocks the event loop, freezing animations, touch responses, and navigation during large data transfers. ISO 25010:2011 performance-efficiency.time-behaviour requires that background operations do not degrade foreground frame rate. A frozen UI during sync is indistinguishable from a crash for the user — they force-quit the app, potentially interrupting the sync and corrupting queue state. Sync must be non-blocking even when processing hundreds of queued records.

## Severity rationale

Medium because UI freezes degrade perceived reliability and can interrupt sync mid-flight, but the defect does not expose data or enable exploitation.

## Remediation

Move heavy sync work to a background task using `react-native-background-fetch` or Expo's `TaskManager`. For foreground sync, ensure every I/O operation uses `async/await` and never calls synchronous storage APIs.

```tsx
// npm install react-native-background-fetch
import BackgroundFetch from 'react-native-background-fetch';

export function registerBackgroundSync() {
  BackgroundFetch.configure(
    { minimumFetchInterval: 15, stopOnTerminate: false, startOnBoot: true },
    async (taskId) => {
      try {
        await drainQueue(executeAction);
        await fetchRemoteUpdates();
      } finally {
        BackgroundFetch.finish(taskId);
      }
    },
    (err) => console.error('BackgroundFetch failed to start:', err)
  );
}
```

For in-app sync, never use `AsyncStorage.getItemSync` or equivalent; every call must be awaited. Wrap sync triggers in a debounce so rapid reconnect/disconnect cycles don't spawn concurrent sync runs.

## Detection

- **ID:** `non-blocking-sync`
- **Severity:** `medium`
- **What to look for:** Examine how data syncing is implemented. Look for use of background tasks, web workers, or non-blocking async patterns. Check that sync operations don't freeze the UI.
- **Pass criteria:** Count all sync operation call sites. Sync operations run asynchronously (using async/await or Promise patterns) without blocking the main UI thread. App remains interactive during sync. At least 1 sync function uses non-blocking async patterns.
- **Fail criteria:** Sync operations run synchronously on the main thread and freeze the UI during large data transfers.
- **Skip (N/A) when:** Never — non-blocking sync is essential for user experience.
- **Detail on fail:** `"Data sync runs on main thread. App freezes for 3-5 seconds during sync, making UI unresponsive."`
- **Remediation:** Use background task scheduling:

  ```tsx
  // Install: npm install react-native-background-fetch

  import BackgroundFetch from 'react-native-background-fetch';

  BackgroundFetch.configure(
    {
      minimumFetchInterval: 15, // minutes
      stopOnTerminate: false,
      startOnBoot: true,
    },
    async (taskId) => {
      console.log('Background sync task:', taskId);

      try {
        await processQueue();
        await syncData();
        BackgroundFetch.finish(taskId);
      } catch (error) {
        console.error('Background sync failed:', error);
        BackgroundFetch.finish(taskId);
      }
    },
    (error) => {
      console.error('BackgroundFetch error:', error);
    }
  );
  ```

---

## External references

- iso-25010 performance-efficiency.time-behaviour

Taxons: user-experience

HTML version: https://auditbuffet.com/patterns/ab-001880
