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:
- Query all users with active wearable connections
- 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_syncevent
- 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:
- Query all active CGM connections
- For each connection:
- Refresh OAuth tokens if needed
- Fetch glucose readings since
lastSyncAt - Store in
patient_glucose_readings - Update
lastSyncAton 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
| Error | Handling |
|---|---|
| Token expired | Auto-refresh; if refresh fails, mark connection as inactive |
| Rate limited | Exponential backoff with retry |
| API unavailable | Retry up to 3 times, then skip user |
| Invalid data | Log warning, skip individual reading |
| Network timeout | 30-second timeout, retry |
Monitoring
Sync job health is monitored via:
- Trigger.dev dashboard — Job status, duration, failure rates
- Sentry — Error tracking and alerting
- Patient events —
wearable_syncevents for audit trail