Skip to main content

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:

OutboxSource of rowsReplay method
SITSyncQueueApproved financial transactionsISITCoreBankingReplay.ReplayAsync(SITTransaction, ct)
SITAccountStateChangeBlock / Unblock commandsISITCoreBankingReplay.ReplayAccountStateChangeAsync(SITAccountStateChange, ct)

Retry policy (both queues)​

SettingValue
Batch size50 rows per tick
BackoffExponential — Math.Min(600, Math.Pow(2, Attempts)) seconds
Dead-letterAfter 10 attempts, status flips to DeadLettered
PersistenceEvery attempt updates Attempts, LastAttemptAt, NextAttemptAt, LastError

A successful replay updates the source row:

  • SITSyncQueue → marks the linked SITTransaction.IsSync = true, records CoreBankingReference, SyncedToCoreAt.
  • SITAccountStateChange → marks the row Succeeded, records CoreBankingReference, 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​

StatusCause
400None of sitTransactionId, transactionReference, requeueDeadLettered=true provided
404Transaction not found
409Transaction 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:

  1. Confirm a real ISITCoreBankingReplay adapter is registered (the Null shim returns 503 / IsSuccessful = false).
  2. Watch the worker logs — SITSyncHostedService polls every 30s and drains 50 rows per tick.
  3. For accounts where you suspect drift, call SITSyncAccountCommand.
  4. For dead-lettered transactions (after 10 failed attempts), call SITSyncTransactionCommand with requeueDeadLettered: true once the root cause is fixed.
  5. Pending-approval transactions (ApprovalStatus = PendingApproval) are not in the replay queue — they need explicit approval first.