acc-create-saga-pattern
1
总安装量
1
周安装量
#44996
全站排名
安装命令
npx skills add https://github.com/dykyi-roman/awesome-claude-code --skill acc-create-saga-pattern
Agent 安装分布
opencode
1
claude-code
1
Skill 文档
Saga Pattern Generator
Creates Saga pattern infrastructure for distributed transaction coordination.
When to Use
- Distributed transactions across multiple services
- Long-running business processes
- Operations requiring compensation on failure
- Multi-step workflows with rollback capability
Component Characteristics
SagaState Enum
- Domain layer enum
- Defines saga lifecycle states: Pending, Running, Compensating, Completed, Failed, CompensationFailed
- Includes state transition validation
- Terminal states detection
SagaStep Interface
- Domain layer interface
- Execute and compensate methods
- Idempotency declaration
- Timeout configuration
SagaContext
- Carries saga execution data
- Serializable for persistence
- Supports data accumulation across steps
SagaOrchestrator
- Application layer coordinator
- Manages step execution
- Handles compensation flow (reverse order)
- Persists state after each step
SagaPersistence
- Stores saga state for recovery
- Supports finding incomplete sagas
- Dead letter handling
Generation Process
Step 1: Analyze Request
Determine:
- Context name (Order, Payment, Shipping)
- Required saga steps
- Compensation logic for each step
Step 2: Generate Core Components
Create in this order:
-
Domain Layer (
src/Domain/Shared/Saga/)SagaState.phpâ State enum with transitionsStepResult.phpâ Step result value objectSagaStepInterface.phpâ Step contractSagaContext.phpâ Execution contextSagaResult.phpâ Saga result- Exception classes
-
Application Layer (
src/Application/Shared/Saga/)SagaPersistenceInterface.phpâ Persistence portSagaRecord.phpâ Persisted recordAbstractSagaStep.phpâ Base step classSagaOrchestrator.phpâ Orchestrator
-
Infrastructure Layer
DoctrineSagaPersistence.phpâ Doctrine implementation- Database migration
-
Tests
SagaStateTest.phpSagaOrchestratorTest.php
Step 3: Generate Context-Specific Steps
For each saga step (e.g., Order saga):
src/Application/{Context}/Saga/Step/
âââ ReserveInventoryStep.php
âââ ChargePaymentStep.php
âââ CreateShipmentStep.php
src/Application/{Context}/Saga/
âââ {Context}SagaFactory.php
File Placement
| Layer | Path |
|---|---|
| Domain Types | src/Domain/Shared/Saga/ |
| Application Saga | src/Application/Shared/Saga/ |
| Context Steps | src/Application/{Context}/Saga/Step/ |
| Saga Factory | src/Application/{Context}/Saga/ |
| Infrastructure | src/Infrastructure/Persistence/Doctrine/Repository/ |
| Unit Tests | tests/Unit/{Layer}/{Path}/ |
Key Principles
Compensation Rules
- Compensate in reverse order of execution
- Compensations must be idempotent
- Handle “already compensated” gracefully
- Log all compensation attempts
Idempotency
- Use idempotency keys for each step
- Check for existing results before executing
- Return existing result if found
State Transitions
Pending â Running â Completed
â
Compensating â Failed
â
CompensationFailed
Naming Conventions
| Component | Pattern | Example |
|---|---|---|
| State Enum | SagaState |
SagaState |
| Step Interface | SagaStepInterface |
SagaStepInterface |
| Abstract Step | AbstractSagaStep |
AbstractSagaStep |
| Concrete Step | {Action}Step |
ReserveInventoryStep |
| Orchestrator | SagaOrchestrator |
SagaOrchestrator |
| Factory | {Name}SagaFactory |
OrderSagaFactory |
| Test | {ClassName}Test |
SagaOrchestratorTest |
Quick Template Reference
SagaStepInterface
interface SagaStepInterface
{
public function name(): string;
public function execute(SagaContext $context): StepResult;
public function compensate(SagaContext $context): StepResult;
public function isIdempotent(): bool;
public function timeout(): int;
}
StepResult
final readonly class StepResult
{
public static function success(array $data = []): self;
public static function failure(string $error): self;
public function isSuccess(): bool;
public function isFailure(): bool;
}
Concrete Step Pattern
final readonly class {Action}Step extends AbstractSagaStep
{
public function name(): string
{
return '{action_name}';
}
public function execute(SagaContext $context): StepResult
{
$idempotencyKey = $this->idempotencyKey($context);
// Check for existing result (idempotency)
// Execute action
// Return StepResult::success([...data...]) or failure
}
public function compensate(SagaContext $context): StepResult
{
// Get data from context
// Undo action
// Handle "already undone" gracefully
return StepResult::success();
}
}
Usage Example
// Create saga
$saga = $orderSagaFactory->create($command);
// Execute
$result = $saga->execute();
if ($result->isCompleted()) {
// Success
} elseif ($result->isFailed()) {
// Failed but compensated
$error = $result->error;
} elseif ($result->isCompensationFailed()) {
// Needs manual intervention
$originalError = $result->error;
$compensationError = $result->compensationError;
}
DI Configuration
# Symfony services.yaml
Domain\Shared\Saga\SagaStepInterface:
tags: ['saga.step']
Application\Shared\Saga\SagaPersistenceInterface:
alias: Infrastructure\Persistence\Doctrine\Repository\DoctrineSagaPersistence
Application\Order\Saga\OrderSagaFactory:
arguments:
$reserveStep: '@Application\Order\Saga\Step\ReserveInventoryStep'
$chargeStep: '@Application\Order\Saga\Step\ChargePaymentStep'
$shipStep: '@Application\Order\Saga\Step\CreateShipmentStep'
Database Schema
CREATE TABLE sagas (
id VARCHAR(255) PRIMARY KEY,
type VARCHAR(255) NOT NULL,
state VARCHAR(50) NOT NULL,
completed_steps JSONB NOT NULL DEFAULT '[]',
context JSONB NOT NULL,
error TEXT,
created_at TIMESTAMP(6) NOT NULL,
updated_at TIMESTAMP(6) NOT NULL,
completed_at TIMESTAMP(6)
);
CREATE INDEX idx_sagas_state ON sagas (state);
CREATE INDEX idx_sagas_type_state ON sagas (type, state);
References
For complete PHP templates and test examples, see:
references/templates.mdâ All component templatesreferences/examples.mdâ Order saga example and unit tests