eng-mmustafa/laravel-saga-workflow
Composer 安装命令:
composer require eng-mmustafa/laravel-saga-workflow
包简介
A powerful Laravel package implementing the Saga Pattern for managing long-running distributed transactions with automatic compensation logic. Build robust, fault-tolerant applications with step-by-step transaction management and automatic rollback capabilities.
关键字:
README 文档
README
A powerful Laravel package that implements the Saga Pattern for managing long-running processes and distributed transactions with automatic compensation logic.
Features
- 🚀 Easy to Use: Simple, intuitive API for defining and executing sagas
- 🔄 Automatic Compensation: Built-in rollback mechanism when steps fail
- 📊 Step-by-Step Execution: Sequential execution with progress tracking
- 🎯 Event-Driven: Rich event system for monitoring saga lifecycle
- 💾 Persistent State: Database storage for saga state and context
- ⚡ Retry Logic: Configurable retry attempts for failed sagas
- 📝 Comprehensive Logging: Detailed logging for debugging and monitoring
- 🧪 Fully Tested: Comprehensive test suite included
Installation
You can install the package via composer:
composer require eng-mmustafa/laravel-saga-workflow
Publish and run migrations
php artisan vendor:publish --tag="saga-migrations"
php artisan migrate
Publish configuration file (optional)
php artisan vendor:publish --tag="saga-config"
Quick Start
1. Create a Step
First, create a step by extending the AbstractStep class:
<?php namespace App\Sagas\Steps; use EngMMustafa\LaravelSagaWorkflow\Core\AbstractStep; class CreateOrderStep extends AbstractStep { public function handle(array $context): array { // Your business logic here $orderId = $this->createOrder($context['customer_id'], $context['items']); $this->logInfo('Order created successfully', ['order_id' => $orderId]); return array_merge($context, ['order_id' => $orderId]); } protected function doCompensate(array $context): void { // Compensation logic - rollback the order creation if (isset($context['order_id'])) { $this->cancelOrder($context['order_id']); $this->logInfo('Order cancelled during compensation'); } } private function createOrder(int $customerId, array $items): int { // Your order creation logic return Order::create([ 'customer_id' => $customerId, 'items' => $items, 'status' => 'pending' ])->id; } private function cancelOrder(int $orderId): void { Order::find($orderId)?->update(['status' => 'cancelled']); } }
2. Create a Saga
Create a saga by extending the AbstractSaga class:
<?php namespace App\Sagas; use EngMMustafa\LaravelSagaWorkflow\Core\AbstractSaga; use App\Sagas\Steps\CreateOrderStep; use App\Sagas\Steps\ProcessPaymentStep; use App\Sagas\Steps\UpdateInventoryStep; use App\Sagas\Steps\SendConfirmationStep; class OrderProcessingSaga extends AbstractSaga { protected function defineName(): string { return 'OrderProcessing'; } protected function defineSteps(): void { $this->addStep(new CreateOrderStep()) ->addStep(new ProcessPaymentStep()) ->addStep(new UpdateInventoryStep()) ->addStep(new SendConfirmationStep()); } }
3. Execute the Saga
Execute your saga using the SagaManager:
<?php namespace App\Http\Controllers; use App\Sagas\OrderProcessingSaga; use EngMMustafa\LaravelSagaWorkflow\Core\SagaManager; use EngMMustafa\LaravelSagaWorkflow\Exceptions\SagaExecutionException; class OrderController extends Controller { public function __construct( private SagaManager $sagaManager ) {} public function processOrder(Request $request) { try { // Create saga with initial context $saga = new OrderProcessingSaga(context: [ 'customer_id' => $request->customer_id, 'items' => $request->items, 'payment_method' => $request->payment_method ]); // Execute the saga $result = $this->sagaManager->execute($saga); return response()->json([ 'success' => true, 'saga_id' => $saga->getId(), 'result' => $result ]); } catch (SagaExecutionException $e) { return response()->json([ 'success' => false, 'error' => $e->getMessage(), 'saga_id' => $e->getSagaId() ], 422); } } public function getSagaStatus(string $sagaId) { $status = $this->sagaManager->getStatus($sagaId); if (!$status) { return response()->json(['error' => 'Saga not found'], 404); } return response()->json($status); } }
Advanced Usage
Custom Step Configuration
You can create more sophisticated steps with custom configuration:
class PaymentStep extends AbstractStep { public function __construct( private PaymentService $paymentService, private string $provider = 'stripe' ) { parent::__construct('ProcessPayment'); } public function handle(array $context): array { $paymentResult = $this->paymentService->charge( $context['amount'], $context['payment_method'], $this->provider ); if (!$paymentResult->successful) { throw new PaymentFailedException('Payment processing failed'); } return array_merge($context, [ 'payment_id' => $paymentResult->id, 'transaction_id' => $paymentResult->transaction_id ]); } protected function doCompensate(array $context): void { if (isset($context['payment_id'])) { $this->paymentService->refund($context['payment_id']); } } }
Event Listeners
Listen to saga events for monitoring and logging:
<?php namespace App\Listeners; use EngMMustafa\LaravelSagaWorkflow\Events\SagaStarted; use EngMMustafa\LaravelSagaWorkflow\Events\SagaCompleted; use EngMMustafa\LaravelSagaWorkflow\Events\SagaFailed; use Illuminate\Support\Facades\Log; class SagaEventListener { public function handleSagaStarted(SagaStarted $event): void { Log::info('Saga started', [ 'saga_id' => $event->getSagaId(), 'saga_name' => $event->getSagaName() ]); } public function handleSagaCompleted(SagaCompleted $event): void { Log::info('Saga completed successfully', [ 'saga_id' => $event->getSagaId(), 'execution_time' => $event->getTotalExecutionTimeInSeconds() ]); } public function handleSagaFailed(SagaFailed $event): void { Log::error('Saga failed', [ 'saga_id' => $event->getSagaId(), 'failed_step' => $event->getFailedStepName(), 'error' => $event->getErrorMessage() ]); } }
Register the listeners in your EventServiceProvider:
protected $listen = [ SagaStarted::class => [SagaEventListener::class . '@handleSagaStarted'], SagaCompleted::class => [SagaEventListener::class . '@handleSagaCompleted'], SagaFailed::class => [SagaEventListener::class . '@handleSagaFailed'], ];
Retry Failed Sagas
public function retrySaga(string $sagaId) { try { // Recreate the saga instance $saga = new OrderProcessingSaga(); // Retry the saga $result = $this->sagaManager->retry($sagaId, $saga); return response()->json(['success' => true, 'result' => $result]); } catch (SagaExecutionException $e) { return response()->json(['error' => $e->getMessage()], 422); } }
Queue Integration
You can easily integrate sagas with Laravel queues:
<?php namespace App\Jobs; use App\Sagas\OrderProcessingSaga; use EngMMustafa\LaravelSagaWorkflow\Core\SagaManager; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; class ProcessOrderSaga implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public function __construct( private array $orderData ) {} public function handle(SagaManager $sagaManager): void { $saga = new OrderProcessingSaga(context: $this->orderData); $sagaManager->execute($saga); } }
Configuration
The package comes with a comprehensive configuration file. Here are the key options:
return [ 'defaults' => [ 'max_retries' => 3, 'retryable' => true, 'timeout' => 300, ], 'logging' => [ 'enabled' => true, 'channel' => 'default', 'log_steps' => true, 'log_compensation' => true, ], 'events' => [ 'enabled' => true, 'queue_listeners' => false, ], 'cleanup' => [ 'enabled' => true, 'completed_retention_days' => 30, 'failed_retention_days' => 90, ], ];
Available Events
The package dispatches the following events:
SagaStarted- When saga execution beginsSagaStepCompleted- When a step completes successfullySagaStepFailed- When a step failsSagaCompleted- When saga completes successfullySagaFailed- When saga fails and compensation begins
Testing
composer test
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security related issues, please email eng.mmustafa@example.com instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see License File for more information.
Changelog
Please see CHANGELOG for more information what has changed recently.# laravel-saga-workflow
eng-mmustafa/laravel-saga-workflow 适用场景与选型建议
eng-mmustafa/laravel-saga-workflow 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 0 次下载、GitHub Stars 达 3, 最近一次更新时间为 2025 年 10 月 26 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「workflow」 「laravel」 「cqrs」 「rollback」 「event-sourcing」 「orchestration」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 eng-mmustafa/laravel-saga-workflow 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 eng-mmustafa/laravel-saga-workflow 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 eng-mmustafa/laravel-saga-workflow 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Workflow for NetCommons Plugin
Interfaces, Traits and Nominal Classes used by Domain Entities Implementing Domain Events
Implementation of the transactional outbox pattern on top of rekalogika/domain-event
Workflow logger
Symfony bundle for broadway/broadway.
Approval Workflow Engine for Filament
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 3
- 点击次数: 35
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-10-26