Skip to Content
WearablesData Sync & Jobs

Data Sync & Background Jobs

Wearable data synchronization is managed by Trigger.dev background jobs that run on automated schedules.

Sync Jobs

syncWearablesDaily

Schedule: Daily at 3:00 AM UTC

Syncs data from all connected wearable devices (Oura, Whoop).

Process:

  1. Query all users with active wearable connections
  2. For each user and device:
    • Refresh OAuth tokens if expired
    • Fetch data from the device API for the last 24 hours
    • Normalize metrics to the standard schema
    • Store in patient_graph.wearable_data
    • Record a wearable_sync event
  3. Handle failures gracefully (log and continue to next user)

Configuration:

// apps/trigger/src/jobs/sync-wearables-daily.ts export const syncWearablesDaily = task({ id: 'sync-wearables-daily', maxDuration: 300, // 5 minutes retry: { maxAttempts: 3, }, });

syncWhoopData

Schedule: Daily

Dedicated Whoop data sync job for recovery, strain, sleep, and workout data.

syncCgmReadings

Schedule: Every 30 minutes

Syncs CGM readings from Dexcom and Libre devices.

Process:

  1. Query all active CGM connections
  2. For each connection:
    • Refresh OAuth tokens if needed
    • Fetch glucose readings since lastSyncAt
    • Store in patient_glucose_readings
    • Update lastSyncAt on the connection record

aggregateWearableData

Schedule: Daily after sync jobs

Computes daily statistics from raw wearable readings:

  • Average, min, max for each metric type
  • Rolling 7-day and 30-day averages
  • Stores in patient_wearable_daily_stats

cleanupWearableData

Schedule: Weekly

Removes expired or redundant wearable data:

  • Raw readings older than 90 days (daily stats are retained)
  • Orphaned records from disconnected devices
  • Duplicate readings

Manual Sync

Users can trigger a manual sync from the consumer app:

curl -X POST "https://my.loop.health/api/patient-graph/wearables/sync" \ -H "Authorization: Bearer $CLERK_JWT" \ -H "Content-Type: application/json" \ -d '{ "source": "oura" }'

Or for the generic wearable endpoint:

curl -X POST "https://my.loop.health/api/wearables/oura/sync" \ -H "Authorization: Bearer $CLERK_JWT"

Error Handling

ErrorHandling
Token expiredAuto-refresh; if refresh fails, mark connection as inactive
Rate limitedExponential backoff with retry
API unavailableRetry up to 3 times, then skip user
Invalid dataLog warning, skip individual reading
Network timeout30-second timeout, retry

Monitoring

Sync job health is monitored via:

  • Trigger.dev dashboard — Job status, duration, failure rates
  • Sentry — Error tracking and alerting
  • Patient eventswearable_sync events for audit trail