Background jobs
Servicing runs as scheduled sweeps on the admin host's worker. Each is a Warp recurring job, fired on a cron by a distributed-locked scheduler — so it runs once per cluster, not once per instance. The partner host runs none of these; it only serves requests against the same database.
The schedule
| Job | Cron | What it does |
|---|---|---|
| Daily servicing | 02:00 daily | Charge → age → delinquency → late fees, as a chain of continuations (each step waits for the previous, so no step works on stale data). |
| Provisioning | 01:00 daily | Recomputes IFRS-9 provisions and posts the impairment. |
| GL posting | hourly | Posts the sub-ledger to the double-entry general ledger, so the Accounting view trails the loan closely. |
| Disbursement dispatch | every 5 min | Dispatches pending Loanly payouts to the bank rail and retries failed ones (idempotent). See Disbursement. |
| Bank-claim reconciliation | every 15 min | Pulls settled bank-claim payments back and records them. No-ops unless the bank rail is configured. |
| Token cleanup | 03:00 daily | Prunes expired/consumed email tokens and revoked sessions. |
The daily servicing chain
The 02:00 run is a single trigger that enqueues its steps as continuations rather than four
independently-scheduled jobs:
charge due installments
└─▶ age installments
└─▶ delinquency buckets
└─▶ late fees
Chaining (vs. spacing jobs out on separate crons) guarantees each step sees the previous step's committed result — aging never runs before charging finishes, and so on. Each run is logged (start, outcome, duration) and every step is idempotent, so a retry or an overlapping trigger is safe.
Where they're registered
All schedules are registered once at startup (idempotent upsert, under a distributed lock, so it's safe on every instance). Registration is skipped in the Testing environment — tests drive the job handlers directly instead.