Queueing transactions
Queueing means a transaction is first recorded as work to be processed, instead of being applied to the ledger immediately in the same request. Here is how it works: Blnk first saves the transaction in aQUEUED state. After that, a worker picks it up and applies it to the ledger. Transactions that affect the same balance are routed in a way that reduces them clashing with each other, while transactions for unrelated balances can still move in parallel.
By default, Blnk uses the queue when receiving a transaction request. Learn more: Transaction lifecycle
Skipping the queue
Blnk also supports skipping the queue and processing a transaction immediately in the same request by settingskip_queue=true.
In this mode, Blnk no longer relies on the queue and uses the other safeguards to keep balance updates correct.
Distributed Redis balance locks
In Blnk, distributed locks are used to make sure two conflicting transactions don’t update the same balance at the same time. Here’s how it works:- Blnk identifies the balance IDs involved in a transaction request. Next, it acquires Redis-backed locks for those balances before processing begins.
- Blnk locks balances in a consistent order to prevent deadlocks. Without this, one transaction could lock Balance A and wait for Balance B, while another locks Balance B and waits for Balance A creating a deadlock.
- If Blnk cannot acquire all the locks it needs, it releases any locks already acquired, then either waits and retries or fails, depending on your configuration.
- Once the locks are held, Blnk reads the latest balance state, validates the transaction, applies the update, and commits it atomically.
- After the commit, the locks are released.
Optimistic locking at the DB layer
Blnk also uses optimistic locking to make sure that a balance is only updated if it has not changed since it was last read. Instead of holding a database lock from the start, Blnk reads the balance, computes the new value in memory, and then tries to write that update back only if the balance is still in the same version it originally read. If another transaction updated the balance first, the write is rejected. Blnk does this using aversion field on each balance. When a new transaction is recorded:
- Blnk reads the balances and their current
version. - Blnk computes the new balance value in memory, and then tries to update the balance only if the
versionis still the same. - If the update succeeds, the
versionis incremented. - If no row is updated, Blnk treats it as an optimistic locking conflict, which means the balance was changed by another transaction before this write could be applied.
In Blnk, optimistic locking acts as the database-level safety net.Distributed locks prevent conflicting transactions from running at the same time, while optimistic locking checks at write time that the balance has not changed since Blnk last read it.