Skip to content
  • Andrey Azeev's avatar
    cdef0d38
    fix(scheduler): cap Retry-After, add lastSyncFinishedAt, row-count gauge · cdef0d38
    Andrey Azeev authored
    Final whole-branch review, Important C, D, A, E and doc corrections (F).
    
    Important C: `Retry-After` from the source was applied unbounded --
    `Retry-After: 3600` could park one page for an hour, five hours across
    retryAttempts=5, with no overall tick deadline. Delay computation moved
    into a pure `_resolve_backoff_delay` (testable without mocking
    asyncio.sleep) and clamped to `CustomerSourceSettings.
    maxRetryAfterSeconds` (default 30s); negative values clamp to zero.
    
    Important D: `set_sync_status` only wrote three of the four fields the
    design's section 10 lists. Added `lastSyncFinishedAt` (self-stamped,
    same `time.time()` pattern as `updatedAt`) through the `BalanceStore`
    port and both implementations, plus a new
    `bonus_last_sync_attempt_age_seconds` gauge alongside the existing
    age-of-data one -- without it a scheduler that dies right after a
    successful tick looks identical to a healthy one on every existing
    signal.
    
    Important A: `bonus_snapshot_rows` gauge, fed from `meta["count"]`
    which `refresh_snapshot_metrics` already read and discarded -- this is
    the metric that would have surfaced both blockers on a dashboard
    before `bonus_snapshot_age_seconds` had a chance to notice anything.
    
    Important E: `stop_grace_period: 240s` on the `scheduler` service in
    both compose files (measured sweep is 170s) so a redeploy landing
    mid-sweep gets SIGTERM instead of SIGKILL. Loop/stop_event logic
    untouched, per review note -- cancelling a running tick is a follow-up.
    
    Doc corrections (F): README's `APP__HALYK_SNAPSHOT_MAXITEMS` default
    (200000 -> 1000000, matching code) and peak-memory figure (56 MiB ->
    ~130 MB, matching measurement); snapshot schema module/SnapshotResult
    docstrings rewritten as internal DTOs, not HTTP contract, now that
    POST /internal/bonus/snapshot is deleted; new settings documented in
    .env.example.
    
    Claude-Session: https://claude.ai/code/session_01681igANZDJCmrQJaWPNk26
    cdef0d38
    fix(scheduler): cap Retry-After, add lastSyncFinishedAt, row-count gauge
    Andrey Azeev authored
    Final whole-branch review, Important C, D, A, E and doc corrections (F).
    
    Important C: `Retry-After` from the source was applied unbounded --
    `Retry-After: 3600` could park one page for an hour, five hours across
    retryAttempts=5, with no overall tick deadline. Delay computation moved
    into a pure `_resolve_backoff_delay` (testable without mocking
    asyncio.sleep) and clamped to `CustomerSourceSettings.
    maxRetryAfterSeconds` (default 30s); negative values clamp to zero.
    
    Important D: `set_sync_status` only wrote three of the four fields the
    design's section 10 lists. Added `lastSyncFinishedAt` (self-stamped,
    same `time.time()` pattern as `updatedAt`) through the `BalanceStore`
    port and both implementations, plus a new
    `bonus_last_sync_attempt_age_seconds` gauge alongside the existing
    age-of-data one -- without it a scheduler that dies right after a
    successful tick looks identical to a healthy one on every existing
    signal.
    
    Important A: `bonus_snapshot_rows` gauge, fed from `meta["count"]`
    which `refresh_snapshot_metrics` already read and discarded -- this is
    the metric that would have surfaced both blockers on a dashboard
    before `bonus_snapshot_age_seconds` had a chance to notice anything.
    
    Important E: `stop_grace_period: 240s` on the `scheduler` service in
    both compose files (measured sweep is 170s) so a redeploy landing
    mid-sweep gets SIGTERM instead of SIGKILL. Loop/stop_event logic
    untouched, per review note -- cancelling a running tick is a follow-up.
    
    Doc corrections (F): README's `APP__HALYK_SNAPSHOT_MAXITEMS` default
    (200000 -> 1000000, matching code) and peak-memory figure (56 MiB ->
    ~130 MB, matching measurement); snapshot schema module/SnapshotResult
    docstrings rewritten as internal DTOs, not HTTP contract, now that
    POST /internal/bonus/snapshot is deleted; new settings documented in
    .env.example.
    
    Claude-Session: https://claude.ai/code/session_01681igANZDJCmrQJaWPNk26
Loading