Skip to main content
Sightscreen runs five background jobs inside the main server process. They execute on independent timers and coordinate through DynamoDB state.

Job overview

JobPurposeIntervalStatus
LiveScoreJobPoll SportMonks for live score data2.5s (live) / 60s (idle)Active
ActivityPushJobPush Live Activity updates to iOS devicesRuns after each LiveScoreJob cycleLegacy
PrematchNotificationJobSend “starting soon” push notifications60sLegacy
FixtureSyncJobSync fixture metadata from SportMonks6 hoursLegacy
ReplayScoreJobAdvance tape playback for replay matches2.5s (mock mode only)Legacy

System diagram


LiveScoreJob

Polls SportMonks for live match data and writes updated scores to DynamoDB.

What it does

  1. Checks which matches are currently live or about to start.
  2. Fetches score data from SportMonks for those matches.
  3. Writes updated score records to the scores table.
  4. Triggers the ActivityPushJob to propagate changes.

Polling interval

  • 2.5 seconds when at least one match is live.
  • 60 seconds when no matches are live (idle polling to detect new live matches).

Tables read/written

TableOperation
Matches tableRead (to find live matches)
Scores tableWrite (updated score data)
Circuit breaker stateRead/Write

Dependencies

  • SportMonks API — the sole data source for live scores.

Circuit breaker

The job implements a circuit breaker to handle SportMonks outages:
  • Closed (normal): requests flow through.
  • Open (tripped): after N consecutive failures, the job stops calling SportMonks and enters a cooldown period.
  • Half-open: after the cooldown, a single test request is made. If it succeeds, the circuit closes; if it fails, it re-opens.
During a circuit breaker open state, the last known scores remain in DynamoDB. Clients continue to see the most recent data, just not real-time updates.

Reconciliation

On each cycle, the job compares the SportMonks response with the current DynamoDB state. If discrepancies are found (e.g., missed ball events), it overwrites the DynamoDB record with the canonical SportMonks data.

Relevant env vars

VariablePurpose
SPORTMONKS_API_TOKENAPI token for SportMonks
SPORTMONKS_SEASON_IDSeason to query
DISABLE_LIVE_SCORE_JOBSet to true to disable this job
LIVE_SCORE_POLL_INTERVAL_MSOverride the live polling interval
IDLE_SCORE_POLL_INTERVAL_MSOverride the idle polling interval

Failure modes

  • SportMonks down: Circuit breaker opens. Scores freeze at last known state. Auto-recovers when SportMonks returns.
  • DynamoDB write failure: Retried on next cycle. No data loss since SportMonks is the source of truth.
  • Malformed response: Logged and skipped. The existing score record is preserved.

ActivityPushJob

Legacy — scheduled for refactoring. The current implementation documented below will change.
Detects score changes and pushes Live Activity updates to iOS devices via APNs.

What it does

  1. After LiveScoreJob writes new data, computes a hash of the current score state.
  2. Compares the hash to the previously pushed hash.
  3. If different, constructs a Live Activity payload and sends it to all devices subscribed to that match.
  4. Updates the stored hash.

State change detection

The job hashes key score fields (runs, wickets, overs, batting/bowling state) to produce a compact fingerprint. Only when the fingerprint changes does it push an update. This prevents redundant pushes when SportMonks returns identical data across cycles.

Self-heal recovery

If the job detects that a device’s Live Activity is in an inconsistent state (e.g., the activity ended on-device but the backend still thinks it’s active), it:
  1. Sends an end event to terminate the stale activity.
  2. Optionally starts a new activity if the match is still live.

Tables read/written

TableOperation
Scores tableRead (current score state)
Push state tableRead/Write (last pushed hash, device tokens)
Devices tableRead (APNs tokens)
Subscriptions tableRead (which users follow which matches)

Dependencies

  • APNs — Apple Push Notification service for Live Activity updates.

Relevant env vars

VariablePurpose
APNS_KEY_IDAPNs auth key ID
APNS_TEAM_IDApple Developer Team ID
APNS_BUNDLE_IDApp bundle identifier
APNS_KEY_PATHPath to the .p8 private key file
APNS_ENVIRONMENTproduction or sandbox
DISABLE_ACTIVITY_PUSH_JOBSet to true to disable

Failure modes

  • APNs down: Pushes fail silently. Next cycle retries because the hash won’t be updated.
  • Invalid device token: APNs returns an error. The token is marked invalid and removed on next cleanup cycle.
  • Hash collision (extremely unlikely): A real change is missed for one cycle but caught on the next.

PrematchNotificationJob

Legacy — scheduled for refactoring. The current implementation documented below will change.
Sends “match starting soon” push notifications to users who follow upcoming matches.

What it does

  1. Scans for matches starting within the notification window (default: 30 minutes).
  2. Looks up users who follow those matches.
  3. Sends a push notification to each user’s registered devices.
  4. Records that the notification was sent (dedup tracking) to avoid sending duplicates.

Polling interval

Runs every 60 seconds.

Tables read/written

TableOperation
Matches tableRead (upcoming matches)
Subscriptions tableRead (followers for each match)
Devices tableRead (APNs tokens)
Notifications tracking tableRead/Write (dedup records)

Dependencies

  • APNs — for sending push notifications.

Dedup tracking

Each (matchId, userId) pair is recorded after the notification is sent. If the job restarts or re-scans, it skips pairs that already have a record.

Relevant env vars

VariablePurpose
DISABLE_PREMATCH_NOTIFICATION_JOBSet to true to disable
PREMATCH_NOTIFICATION_WINDOW_MINUTESHow many minutes before start to notify (default: 30)

Failure modes

  • APNs failure: Notification is not marked as sent. Will retry on next cycle.
  • DynamoDB read failure: Job skips the cycle and retries next interval.
  • Duplicate sends on restart: Mitigated by dedup tracking. If tracking write fails, the user may receive a duplicate — acceptable for “starting soon” alerts.

FixtureSyncJob

Legacy — scheduled for refactoring. The current implementation documented below will change.
Periodically syncs fixture metadata (start times, venues, team assignments) from SportMonks.

What it does

  1. Fetches the fixture list for the configured season from SportMonks.
  2. Compares with existing fixture records in DynamoDB.
  3. Updates any changed fields (start time, venue, status).
  4. Creates records for newly discovered fixtures.

Polling interval

Runs every 6 hours.

Tables read/written

TableOperation
Matches tableRead/Write (fixture metadata)
Leagues tableRead (to map SportMonks league IDs)

Dependencies

  • SportMonks API — fixture list endpoint.

Relevant env vars

VariablePurpose
SPORTMONKS_API_TOKENAPI token for SportMonks
SPORTMONKS_SEASON_IDSeason to sync
DISABLE_FIXTURE_SYNC_JOBSet to true to disable
FIXTURE_SYNC_INTERVAL_MSOverride the sync interval

Failure modes

  • SportMonks down: Sync skipped. Existing fixture data remains unchanged. Retries on next cycle.
  • Partial response: The job processes whatever fixtures are returned. Missing fixtures remain unchanged.

ReplayScoreJob

Legacy — scheduled for refactoring. The current implementation documented below will change.
Advances tape playback for replay matches. Only active in mock mode.

What it does

  1. Reads active replay matches and their associated tapes.
  2. For each replay match, advances the tape by one step (one ball/event).
  3. Writes the new score state to the scores table, mimicking what LiveScoreJob would write for a real match.
  4. Triggers ActivityPushJob to push the update to devices.

Polling interval

Runs every 2.5 seconds (same cadence as LiveScoreJob for realistic simulation).

Tables read/written

TableOperation
Replay matches tableRead (active replays, playback state)
Tapes tableRead (recorded match data)
Scores tableWrite (mock score data)
Replay matches tableWrite (advance playback position)

Dependencies

  • No external dependencies. Operates entirely on local DynamoDB data.

Relevant env vars

VariablePurpose
MOCK_SPORTMONKS_URLURL of the mock SportMonks server
MOCK_SPORTMONKS_TOKENToken for the mock server
DISABLE_REPLAY_SCORE_JOBSet to true to disable

Failure modes

  • Missing tape data: Replay stops at the last available position. Logged as a warning.
  • DynamoDB write failure: Retried on next cycle. Playback position is not advanced until the write succeeds.
ReplayScoreJob should never be enabled in production. It is gated behind mock mode configuration.