Skip to content

@breadstone/ziegel-platform-transaction ​

MIT LicenseTypeScriptnpm

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 ​

bash
npm install @breadstone/ziegel-platform-transaction
# or
yarn add @breadstone/ziegel-platform-transaction

🧩 Features & Usage Examples ​

Basic Transactions ​

typescript
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 ​

typescript
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) ​

typescript
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 ​

typescript
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 ​

typescript
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

  • @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&lt;string, any&gt; = 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 ​

typescript
class DataTransactionManager extends TransactorBase {
  private readonly state: ApplicationState;

  constructor() {
    super();
    this.state = new ApplicationState();
  }

  public async performBulkUpdate(updates: Array&lt;{ key: string; value: any }&gt;): Promise&lt;void&gt; {
    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&lt;void&gt; {
    this.previousValue = this.state.get(this.key);
    this.state.set(this.key, this.value);
  }

  public async undo(): Promise&lt;void&gt; {
    this.state.set(this.key, this.previousValue);
  }

  public canUndo(): boolean {
    return true;
  }
}

Nested Transactions ​

typescript
class NestedTransactionExample {
  private transactor = new Transactor();

  public async performComplexOperation(): Promise&lt;void&gt; {
    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 ​

typescript
import { Subject } from 'rxjs';

class EventDrivenTransactor extends TransactorBase {
  private stateUpdates$ = new Subject<IStateUpdateEvent&gt;();

  public get stateUpdates(): Observable<IStateUpdateEvent&gt; {
    return this.stateUpdates$.asObservable();
  }

  protected onStateUpdate(event: IStateUpdateEvent): void {
    this.stateUpdates$.next(event);
  }

  public async executeWithEvents(actions: IAction[]): Promise&lt;void&gt; {
    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 ​

typescript
enum TransactionType {
  ReadOnly = 'readonly',
  ReadWrite = 'readwrite'
}

// Configure transaction behavior
const transactionConfig = {
  autoCommit: false,
  isolationLevel: 'read-committed',
  timeout: 30000, // 30 seconds
  maxRetries: 3
};

Transactor Configuration ​

typescript
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 ​

typescript
class CompensatingTransaction {
  private compensationActions: IAction[] = [];

  public async executeWithCompensation(action: IAction): Promise&lt;void&gt; {
    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 ​

typescript
class LoggingTransactor extends TransactorBase {
  private logger: ILogger;

  constructor(logger: ILogger) {
    super();
    this.logger = logger;
  }

  public async begin(type: TransactionType): Promise&lt;ITransaction&gt; {
    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 ​

typescript
class PerformanceMonitoringTransactor extends TransactorBase {
  private metrics = new Map&lt;string, number&gt;();

  public async executeWithMetrics(action: IAction): Promise&lt;void&gt; {
    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&lt;string, number&gt; {
    return new Map(this.metrics);
  }
}

Integration Examples ​

React Integration ​

typescript
import React, { createContext, useContext } from 'react';
import { Transactor } from '@breadstone/ziegel-platform-transaction';

const TransactionContext = createContext<Transactor | null&gt;(null);

export const TransactionProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const transactor = new Transactor();

  return (
    <TransactionContext.Provider value={transactor}>
      {children}
    </TransactionContext.Provider&gt;
  );
};

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&gt;;
};

Angular Integration ​

typescript
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&gt;(
    operation: () => Promise&lt;T&gt;,
    type: TransactionType = TransactionType.ReadWrite
  ): Promise&lt;T&gt; {
    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 ​

typescript
// Keep actions focused and atomic
class UpdateUserEmailAction implements IAction {
  private previousEmail: string;

  constructor(private userId: string, private newEmail: string) {}

  public async execute(): Promise&lt;void&gt; {
    const user = await this.userService.getUser(this.userId);
    this.previousEmail = user.email;
    await this.userService.updateEmail(this.userId, this.newEmail);
  }

  public async undo(): Promise&lt;void&gt; {
    await this.userService.updateEmail(this.userId, this.previousEmail);
  }

  public canUndo(): boolean {
    return this.previousEmail !== undefined;
  }
}

2. Error Handling ​

typescript
class RobustTransactionManager {
  public async safeExecute(actions: IAction[]): Promise&lt;void&gt; {
    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&lt;void&gt; {
    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 ​

typescript
class ConsistentStateManager {
  private state = new ApplicationState();
  private stateVersion = 0;

  public async updateWithConsistencyCheck(
    updates: Array&lt;{ key: string; value: any; expectedVersion?: number }&gt;
  ): Promise&lt;void&gt; {
    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 ​

typescript
// Update action implementations to include better undo support
class MyAction implements IAction {
  // Before: Simple execute method
  public async execute(): Promise&lt;void&gt; {
    // implementation
  }

  // After: Add undo support
  public async undo(): Promise&lt;void&gt; {
    // rollback implementation
  }

  public canUndo(): boolean {
    return true; // or specific logic
  }
}
  • @breadstone/ziegel-core: Core utilities and patterns
  • @breadstone/ziegel-platform: Platform services integration

Troubleshooting ​

Common Issues ​

  1. Transaction deadlocks: Use appropriate transaction types and avoid long-running operations
  2. Memory leaks: Ensure proper cleanup of transaction resources
  3. Rollback failures: Implement robust undo operations in actions

Debug Configuration ​

typescript
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 transaction
  • getCurrentTransaction(): ITransaction | null - Get active transaction

ITransaction ​

  • execute(action: IAction): Promise&lt;void&gt; - Execute an action
  • commit(): Promise&lt;void&gt; - Commit the transaction
  • rollback(): Promise&lt;void&gt; - Rollback the transaction
  • addAction(action: IAction): void - Add action to transaction

IAction ​

  • execute(): Promise&lt;void&gt; - Execute the action
  • undo(): Promise&lt;void&gt; - Undo the action
  • canUndo(): boolean - Check if action can be undone