@breadstone/ziegel-platform-transaction ​
Enterprise transaction management for the ziegel platform. Provides distributed transactions, compensation patterns, and transactional workflows for enterprise applications.
Transaction Management: Enterprise transaction patterns with distributed transactions, compensation, and workflow coordination.
🚀 Overview ​
@breadstone/ziegel-platform-transaction provides:
- Distributed Transactions: ACID transactions across multiple resources
- Compensation Patterns: Saga pattern implementation for long-running transactions
- Transaction Coordination: Two-phase commit and transaction orchestration
- Isolation Levels: Configurable transaction isolation levels
- Deadlock Detection: Automatic deadlock detection and resolution
- Transaction Logging: Comprehensive transaction audit trails
📦 Installation ​
npm install @breadstone/ziegel-platform-transaction
# or
yarn add @breadstone/ziegel-platform-transaction🧩 Features & Usage Examples ​
Basic Transactions ​
import { TransactionManager, Transactional } from '@breadstone/ziegel-platform-transaction';
class UserService {
@Transactional()
async createUser(userData: CreateUserRequest) {
// All operations in this method run in a transaction
const user = await this.userRepository.create(userData);
await this.auditService.logUserCreation(user.id);
return user;
}
}Distributed Transactions ​
import { DistributedTransactionManager, TransactionScope } from '@breadstone/ziegel-platform-transaction';
const txManager = new DistributedTransactionManager();
await txManager.execute(async (scope: TransactionScope) => {
await scope.enlist(databaseA);
await scope.enlist(databaseB);
await databaseA.updateAccount(accountId, -amount);
await databaseB.updateAccount(targetAccountId, amount);
});Saga Pattern (Compensation) ​
import { SagaOrchestrator, SagaStep } from '@breadstone/ziegel-platform-transaction';
class OrderSaga extends SagaOrchestrator {
async execute(order: Order) {
await this.addStep(new SagaStep(
() => this.reserveInventory(order),
() => this.releaseInventory(order)
));
await this.addStep(new SagaStep(
() => this.processPayment(order),
() => this.refundPayment(order)
));
await this.addStep(new SagaStep(
() => this.shipOrder(order),
() => this.cancelShipment(order)
));
}
}Transaction Isolation ​
import { IsolationLevel, TransactionOptions } from '@breadstone/ziegel-platform-transaction';
const options: TransactionOptions = {
isolationLevel: IsolationLevel.ReadCommitted,
timeout: 30000,
readOnly: false
};
await transactionManager.executeWithOptions(options, async () => {
// Transaction logic with specific isolation level
});📚 Package import points ​
import {
// Core Transaction Management
TransactionManager,
DistributedTransactionManager,
Transactional,
// Saga Pattern
SagaOrchestrator,
SagaStep,
// Configuration
TransactionOptions,
IsolationLevel,
TransactionScope,
// Utilities
TransactionContext,
CompensationAction
} from '@breadstone/ziegel-platform-transaction';📚 API Documentation ​
For detailed API documentation, visit: API Docs
Related Packages ​
- @breadstone/ziegel-platform: Core platform services
- @breadstone/ziegel-data: Data access and repository patterns
- @breadstone/ziegel-core: Foundation utilities
License ​
MIT
Issues ​
Please report bugs and feature requests in the Issue Tracker
Part of the ziegel Enterprise TypeScript Framework await this.userService.saveUser(this.user); }
public async undo(): Promise<void> { // Restore previous state if (this.previousState) { await this.userService.saveUser(this.previousState); } }
public canUndo(): boolean { return this.previousState !== undefined; } }
// Use the custom action const saveAction = new SaveUserAction(user); await transaction.execute(saveAction);
### State Management with Transactions
```typescript
import {
IState,
IStateUpdateEvent,
TransactionEventOrigin
} from '@breadstone/ziegel-platform-transaction';
class ApplicationState implements IState {
private data: Map<string, any> = new Map();
private version: number = 0;
public get(key: string): any {
return this.data.get(key);
}
public set(key: string, value: any): void {
this.data.set(key, value);
this.version++;
// Notify about state change
this.onStateUpdate.next({
key,
oldValue: this.data.get(key),
newValue: value,
version: this.version,
origin: TransactionEventOrigin.User
});
}
public getVersion(): number {
return this.version;
}
public createSnapshot(): any {
return {
data: new Map(this.data),
version: this.version
};
}
public restoreSnapshot(snapshot: any): void {
this.data = snapshot.data;
this.version = snapshot.version;
}
}Advanced Transaction Patterns ​
class DataTransactionManager extends TransactorBase {
private readonly state: ApplicationState;
constructor() {
super();
this.state = new ApplicationState();
}
public async performBulkUpdate(updates: Array<{ key: string; value: any }>): Promise<void> {
const transaction = this.begin(TransactionType.ReadWrite);
try {
// Create snapshot before changes
const snapshot = this.state.createSnapshot();
// Add rollback action
transaction.addAction({
execute: async () => {
// Updates will be applied by individual actions
},
undo: async () => {
this.state.restoreSnapshot(snapshot);
},
canUndo: () => true
});
// Apply all updates
for (const update of updates) {
transaction.addAction(new UpdateStateAction(this.state, update.key, update.value));
}
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
}
class UpdateStateAction implements IAction {
private previousValue: any;
constructor(
private state: ApplicationState,
private key: string,
private value: any
) {}
public async execute(): Promise<void> {
this.previousValue = this.state.get(this.key);
this.state.set(this.key, this.value);
}
public async undo(): Promise<void> {
this.state.set(this.key, this.previousValue);
}
public canUndo(): boolean {
return true;
}
}Nested Transactions ​
class NestedTransactionExample {
private transactor = new Transactor();
public async performComplexOperation(): Promise<void> {
const outerTransaction = this.transactor.begin(TransactionType.ReadWrite);
try {
// Perform some operations
await outerTransaction.execute(new InitializeAction());
// Start nested transaction for sub-operations
const innerTransaction = this.transactor.begin(TransactionType.ReadWrite);
try {
await innerTransaction.execute(new SubOperation1Action());
await innerTransaction.execute(new SubOperation2Action());
await innerTransaction.commit();
} catch (error) {
await innerTransaction.rollback();
throw error; // Will cause outer transaction to rollback
}
// Continue with outer transaction
await outerTransaction.execute(new FinalizeAction());
await outerTransaction.commit();
} catch (error) {
await outerTransaction.rollback();
throw error;
}
}
}Event-Driven Transactions ​
import { Subject } from 'rxjs';
class EventDrivenTransactor extends TransactorBase {
private stateUpdates$ = new Subject<IStateUpdateEvent>();
public get stateUpdates(): Observable<IStateUpdateEvent> {
return this.stateUpdates$.asObservable();
}
protected onStateUpdate(event: IStateUpdateEvent): void {
this.stateUpdates$.next(event);
}
public async executeWithEvents(actions: IAction[]): Promise<void> {
const transaction = this.begin(TransactionType.ReadWrite);
try {
for (const action of actions) {
await transaction.execute(action);
// Emit state update event
this.onStateUpdate({
origin: TransactionEventOrigin.System,
timestamp: new Date(),
actionType: action.constructor.name
});
}
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
}Configuration Options ​
Transaction Types ​
enum TransactionType {
ReadOnly = 'readonly',
ReadWrite = 'readwrite'
}
// Configure transaction behavior
const transactionConfig = {
autoCommit: false,
isolationLevel: 'read-committed',
timeout: 30000, // 30 seconds
maxRetries: 3
};Transactor Configuration ​
class ConfigurableTransactor extends TransactorBase {
constructor(private config: TransactionConfig) {
super();
}
protected createTransaction(type: TransactionType): ITransaction {
const transaction = super.createTransaction(type);
// Apply configuration
if (this.config.timeout) {
transaction.setTimeout(this.config.timeout);
}
if (this.config.autoCommit) {
transaction.enableAutoCommit();
}
return transaction;
}
}Advanced Features ​
Compensation Actions ​
class CompensatingTransaction {
private compensationActions: IAction[] = [];
public async executeWithCompensation(action: IAction): Promise<void> {
try {
await action.execute();
// Add compensation action
this.compensationActions.push({
execute: action.undo.bind(action),
undo: action.execute.bind(action),
canUndo: () => action.canUndo()
});
} catch (error) {
// Execute compensation actions in reverse order
for (let i = this.compensationActions.length - 1; i >= 0; i--) {
await this.compensationActions[i].execute();
}
throw error;
}
}
}Transaction Logging ​
class LoggingTransactor extends TransactorBase {
private logger: ILogger;
constructor(logger: ILogger) {
super();
this.logger = logger;
}
public async begin(type: TransactionType): Promise<ITransaction> {
const transaction = await super.begin(type);
this.logger.info(`Transaction started: ${transaction.id} (${type})`);
// Wrap transaction methods for logging
const originalCommit = transaction.commit.bind(transaction);
const originalRollback = transaction.rollback.bind(transaction);
transaction.commit = async () => {
try {
await originalCommit();
this.logger.info(`Transaction committed: ${transaction.id}`);
} catch (error) {
this.logger.error(`Transaction commit failed: ${transaction.id}`, error);
throw error;
}
};
transaction.rollback = async () => {
try {
await originalRollback();
this.logger.info(`Transaction rolled back: ${transaction.id}`);
} catch (error) {
this.logger.error(`Transaction rollback failed: ${transaction.id}`, error);
throw error;
}
};
return transaction;
}
}Performance Monitoring ​
class PerformanceMonitoringTransactor extends TransactorBase {
private metrics = new Map<string, number>();
public async executeWithMetrics(action: IAction): Promise<void> {
const startTime = performance.now();
const actionName = action.constructor.name;
try {
await action.execute();
const duration = performance.now() - startTime;
this.recordMetric(actionName, duration);
} catch (error) {
const duration = performance.now() - startTime;
this.recordMetric(`${actionName}_error`, duration);
throw error;
}
}
private recordMetric(name: string, duration: number): void {
const existing = this.metrics.get(name) || 0;
this.metrics.set(name, existing + duration);
}
public getMetrics(): Map<string, number> {
return new Map(this.metrics);
}
}Integration Examples ​
React Integration ​
import React, { createContext, useContext } from 'react';
import { Transactor } from '@breadstone/ziegel-platform-transaction';
const TransactionContext = createContext<Transactor | null>(null);
export const TransactionProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const transactor = new Transactor();
return (
<TransactionContext.Provider value={transactor}>
{children}
</TransactionContext.Provider>
);
};
export const useTransaction = () => {
const transactor = useContext(TransactionContext);
if (!transactor) {
throw new Error('useTransaction must be used within TransactionProvider');
}
return transactor;
};
// Usage in component
const MyComponent: React.FC = () => {
const transactor = useTransaction();
const handleSave = async () => {
const transaction = transactor.begin(TransactionType.ReadWrite);
try {
await transaction.execute(new SaveDataAction(data));
await transaction.commit();
} catch (error) {
await transaction.rollback();
console.error('Save failed:', error);
}
};
return <button onClick={handleSave}>Save</button>;
};Angular Integration ​
import { Injectable } from '@angular/core';
import { Transactor, TransactionType } from '@breadstone/ziegel-platform-transaction';
@Injectable({
providedIn: 'root'
})
export class TransactionService {
private transactor = new Transactor();
public async executeInTransaction<T>(
operation: () => Promise<T>,
type: TransactionType = TransactionType.ReadWrite
): Promise<T> {
const transaction = this.transactor.begin(type);
try {
const result = await operation();
await transaction.commit();
return result;
} catch (error) {
await transaction.rollback();
throw error;
}
}
}Best Practices ​
1. Action Design ​
// Keep actions focused and atomic
class UpdateUserEmailAction implements IAction {
private previousEmail: string;
constructor(private userId: string, private newEmail: string) {}
public async execute(): Promise<void> {
const user = await this.userService.getUser(this.userId);
this.previousEmail = user.email;
await this.userService.updateEmail(this.userId, this.newEmail);
}
public async undo(): Promise<void> {
await this.userService.updateEmail(this.userId, this.previousEmail);
}
public canUndo(): boolean {
return this.previousEmail !== undefined;
}
}2. Error Handling ​
class RobustTransactionManager {
public async safeExecute(actions: IAction[]): Promise<void> {
const transaction = this.transactor.begin(TransactionType.ReadWrite);
try {
for (const action of actions) {
await this.executeWithRetry(transaction, action);
}
await transaction.commit();
} catch (error) {
await transaction.rollback();
this.handleTransactionError(error);
throw error;
}
}
private async executeWithRetry(
transaction: ITransaction,
action: IAction,
maxRetries: number = 3
): Promise<void> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
await transaction.execute(action);
return;
} catch (error) {
if (attempt === maxRetries) throw error;
await this.delay(attempt * 1000);
}
}
}
}3. State Consistency ​
class ConsistentStateManager {
private state = new ApplicationState();
private stateVersion = 0;
public async updateWithConsistencyCheck(
updates: Array<{ key: string; value: any; expectedVersion?: number }>
): Promise<void> {
const transaction = this.transactor.begin(TransactionType.ReadWrite);
try {
// Check version consistency
for (const update of updates) {
if (update.expectedVersion && update.expectedVersion !== this.stateVersion) {
throw new Error('State version conflict detected');
}
}
// Apply updates
for (const update of updates) {
await transaction.execute(new UpdateStateAction(update.key, update.value));
}
this.stateVersion++;
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
}Migration Guide ​
From Version 0.0.1 to 0.0.2 ​
The transaction package has been enhanced with better error handling and state management.
New Features ​
- Enhanced state tracking with versioning
- Improved rollback mechanisms
- Better integration with RxJS observables
Migration Steps ​
// Update action implementations to include better undo support
class MyAction implements IAction {
// Before: Simple execute method
public async execute(): Promise<void> {
// implementation
}
// After: Add undo support
public async undo(): Promise<void> {
// rollback implementation
}
public canUndo(): boolean {
return true; // or specific logic
}
}Related Packages ​
- @breadstone/ziegel-core: Core utilities and patterns
- @breadstone/ziegel-platform: Platform services integration
Troubleshooting ​
Common Issues ​
- Transaction deadlocks: Use appropriate transaction types and avoid long-running operations
- Memory leaks: Ensure proper cleanup of transaction resources
- Rollback failures: Implement robust undo operations in actions
Debug Configuration ​
const debugTransactor = new Transactor({
debug: true,
logTransactions: true,
validateActions: true
});API Reference ​
For detailed API documentation, see the auto-generated API reference.
ITransactor ​
begin(type: TransactionType): ITransaction- Start a new transactiongetCurrentTransaction(): ITransaction | null- Get active transaction
ITransaction ​
execute(action: IAction): Promise<void>- Execute an actioncommit(): Promise<void>- Commit the transactionrollback(): Promise<void>- Rollback the transactionaddAction(action: IAction): void- Add action to transaction
IAction ​
execute(): Promise<void>- Execute the actionundo(): Promise<void>- Undo the actioncanUndo(): boolean- Check if action can be undone