Overview
In microservice applications, completing a business operation may span multiple services and multiple databases. Distributed transactions ensure that operations across multiple resource servers either all succeed or all fail, maintaining data consistency.
Theoretical Background
CAP Theorem
Distributed systems cannot simultaneously satisfy all three of:
- Consistency (C): All nodes see the same data at the same time
- Availability (A): Every request receives a response within a bounded time
- Partition Tolerance (P): The system continues to operate despite network partitions
Since partition tolerance is mandatory in distributed systems, architects must choose between consistency and availability based on business requirements.
BASE Theory
BASE is an alternative to ACID for large-scale distributed systems:
- Basically Available: The system remains available despite partial failures
- Soft State: Data may be in an intermediate state temporarily
- Eventual Consistency: Data will converge to a consistent state eventually

TCC Transaction
Silky implements the TCC (Try-Confirm-Cancel) distributed transaction pattern.
| Phase | Description |
|---|---|
| Try | Reserve resources; perform preliminary checks and reservations (no actual commit) |
| Confirm | Commit the transaction; execute the actual business operation using reserved resources |
| Cancel | Roll back; release reserved resources if Try or Confirm fails |
Enable TCC Support
PM> Install-Package Silky.Transaction.Tcc -Version 3.9.2
PM> Install-Package Silky.Transaction.Repository.Redis -Version 3.9.2 # Redis journal
Configure
transaction:
retryMax: 10 # max retry attempts for compensation
recoverDelayTime: 60 # delay before recovery attempt (s)
redis:
configuration: "127.0.0.1:6379"
Annotate the Coordinator
Mark the initiating method with [Transaction]:
[ServiceRoute]
public interface IOrderAppService
{
[Transaction]
Task<CreateOrderOutput> CreateOrderAsync(CreateOrderInput input);
}
Implement Try / Confirm / Cancel
Mark participant methods with [TccTransaction], specifying the confirm and cancel method names:
[ServiceRoute]
public interface IInventoryAppService
{
// Try: reserve stock
[TccTransaction(ConfirmMethod = "ConfirmDeductStock", CancelMethod = "CancelDeductStock")]
Task<bool> TryDeductStockAsync(DeductStockInput input);
// Confirm: actually deduct stock
Task<bool> ConfirmDeductStockAsync(DeductStockInput input);
// Cancel: release the reserved stock
Task<bool> CancelDeductStockAsync(DeductStockInput input);
}
Orchestrate the Transaction
In the coordinator's implementation, call participant Try methods. The framework automatically calls Confirm on all participants on success, or Cancel on all on failure:
public class OrderAppService : IOrderAppService, IScopedDependency
{
private readonly IInventoryAppService _inventoryService;
private readonly IAccountAppService _accountService;
public OrderAppService(
IInventoryAppService inventoryService,
IAccountAppService accountService)
{
_inventoryService = inventoryService;
_accountService = accountService;
}
[Transaction]
public async Task<CreateOrderOutput> CreateOrderAsync(CreateOrderInput input)
{
// Step 1: Try deduct stock
await _inventoryService.TryDeductStockAsync(new DeductStockInput
{
ProductId = input.ProductId,
Quantity = input.Quantity
});
// Step 2: Try deduct account balance
await _accountService.TryDeductBalanceAsync(new DeductBalanceInput
{
UserId = input.UserId,
Amount = input.TotalAmount
});
// If any Try fails, the framework automatically calls Cancel on all participants
return new CreateOrderOutput { OrderId = Guid.NewGuid().ToString() };
}
}
Transaction Journal
Silky persists transaction state in Redis, enabling automatic recovery of interrupted transactions:
- Try phase records the participant list and input parameters
- Confirm/Cancel phase updates transaction state
- A background recovery task retries failed compensations up to
transaction:retryMaxtimes
Limitations
- Only the TCC pattern is built-in; Saga and AT modes are not currently supported
- All participant service interfaces must be Silky service entries (annotated with
[ServiceRoute]) - Confirm and Cancel methods must be idempotent — they may be called more than once during recovery
