Sync & Replay
SIL transactions and account state changes are replayed to the core
banking system automatically by SITSyncHostedService. This page covers
the worker, the queues it drains, and the operator commands that let you
nudge or refresh things manually.
SITSyncHostedService​
A BackgroundService registered in Startup.cs. Polls every 30s and
drains two outbox tables:
| Outbox | Source of rows | Replay method |
|---|---|---|
SITSyncQueue | Approved financial transactions | ISITCoreBankingReplay.ReplayAsync(SITTransaction, ct) |
SITAccountStateChange | Block / Unblock commands | ISITCoreBankingReplay.ReplayAccountStateChangeAsync(SITAccountStateChange, ct) |
Retry policy (both queues)​
| Setting | Value |
|---|---|
| Batch size | 50 rows per tick |
| Backoff | Exponential — Math.Min(600, Math.Pow(2, Attempts)) seconds |
| Dead-letter | After 10 attempts, status flips to DeadLettered |
| Persistence | Every attempt updates Attempts, LastAttemptAt, NextAttemptAt, LastError |
A successful replay updates the source row:
SITSyncQueue→ marks the linkedSITTransaction.IsSync = true, recordsCoreBankingReference,SyncedToCoreAt.SITAccountStateChange→ marks the rowSucceeded, recordsCoreBankingReference,SyncedToCoreAt.
Adapter contract​
public interface ISITCoreBankingReplay
{
Task<SITReplayResult> ReplayAsync(SITTransaction transaction, CancellationToken ct);
Task<SITReplayResult> ReplayAccountStateChangeAsync(SITAccountStateChange change, CancellationToken ct);
Task<SITCoreAccountSnapshot> FetchAccountFromCoreAsync(
string accountNumber,
CoreBankingProviderEnum provider,
CancellationToken ct);
}
SITReplayResult.IsRetryable = false causes the worker to dead-letter the
row immediately without burning the remaining attempts (use for definitive
core-side rejections like "duplicate reference").
The default NullSITCoreBankingReplay is a no-op shim. Replace it via DI
with a real BankOne / T24 / Finacle / Flexcube adapter.
SITSyncTransactionCommand​
Operator override that nudges a transaction back into the replay queue. The
hosted worker still does the actual replay; this command just resets the
queue row to Pending so the next poll picks it up.
Cmd: SITSyncTransactionCommand
Modes​
Single transaction​
{
"cmd": "SITSyncTransactionCommand",
"data": { "transactionReference": "DEP-20260427-0001" }
}
or:
{ "data": { "sitTransactionId": "<guid>" } }
Locates the matching SITSyncQueue row (or creates one if missing for
some reason), resets Status = Pending, NextAttemptAt = UtcNow,
Attempts = 0, clears LastError. Next worker tick (≤30s) replays it.
Bulk requeue dead-lettered​
{
"cmd": "SITSyncTransactionCommand",
"data": { "requeueDeadLettered": true }
}
Resurrects every dead-lettered row for the current tenant. Use after fixing the underlying core-side problem (e.g. credentials rotated, vendor outage resolved).
Refusal cases​
| Status | Cause |
|---|---|
400 | None of sitTransactionId, transactionReference, requeueDeadLettered=true provided |
404 | Transaction not found |
409 | Transaction is Pending (not yet approved), Rejected, or already IsSync = true |
Response​
{
"isSuccessful": true,
"message": "1 SIT transaction(s) requeued for replay.",
"data": { "requeued": 1 }
}
SITSyncAccountCommand​
Pull the canonical account + customer snapshot from core and refresh the SIL cache. Documented under Account Management.
This is the inbound sync (CBS → SIL). The two queues above are the outbound syncs (SIL → CBS).
Operational checklist​
When the core banking system comes back online after an outage:
- Confirm a real
ISITCoreBankingReplayadapter is registered (theNullshim returns 503 /IsSuccessful = false). - Watch the worker logs —
SITSyncHostedServicepolls every 30s and drains 50 rows per tick. - For accounts where you suspect drift, call
SITSyncAccountCommand. - For dead-lettered transactions (after 10 failed attempts), call
SITSyncTransactionCommandwithrequeueDeadLettered: trueonce the root cause is fixed. - Pending-approval transactions (
ApprovalStatus = PendingApproval) are not in the replay queue — they need explicit approval first.