[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CVGFS3EZ76BJXCZSB2CF82":3,"skill-same:01M6CVGFS3EZ76BJXCZSB2CF82":62},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":27,"linkOnly":28,"markdownContent":29,"markdownBody":30,"frontMatter":31,"refName":34,"commitSha":35,"skillDirectory":36,"forksCount":37,"repositoryHtmlUrl":38,"repositoryHomepageUrl":38,"ownerHtmlUrl":39,"ownerBlogUrl":6,"ownerDescription":40,"updatedAt":41,"install":42,"resources":55},"01M6CVGFS3EZ76BJXCZSB2CF82","saga-orchestration",null,"Patterns for managing distributed transactions and long-running business processes.","Sam-06060\u002Fjarvis-assistant","Sam-06060","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F208600848?v=4","01M6CRKT7C7FXD21V6HXF293S0","Samson Frank Ganta","01M6CRKTBEKYFD8YX5Z1GT99EE",6,"Apache-2.0","https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fmodules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fsaga-orchestration\u002FSKILL.md",[],[19,20,21,22,23,24,25,26],"orchestration","saga orchestration","saga","distributed","transactions","business","community","patterns","2026-11-10 10:12:30",false,"---\nname: saga-orchestration\ndescription: \"Patterns for managing distributed transactions and long-running business processes.\"\nrisk: unknown\nsource: community\ndate_added: \"2026-02-27\"\n---\n\n# Saga Orchestration\n\nPatterns for managing distributed transactions and long-running business processes.\n\n## Do not use this skill when\n\n- The task is unrelated to saga orchestration\n- You need a different domain or tool outside this scope\n\n## Instructions\n\n- Clarify goals, constraints, and required inputs.\n- Apply relevant best practices and validate outcomes.\n- Provide actionable steps and verification.\n- If detailed examples are required, open `resources\u002Fimplementation-playbook.md`.\n\n## Use this skill when\n\n- Coordinating multi-service transactions\n- Implementing compensating transactions\n- Managing long-running business workflows\n- Handling failures in distributed systems\n- Building order fulfillment processes\n- Implementing approval workflows\n\n## Core Concepts\n\n### 1. Saga Types\n\n```\nChoreography                    Orchestration\n┌─────┐  ┌─────┐  ┌─────┐     ┌─────────────┐\n│Svc A│─►│Svc B│─►│Svc C│     │ Orchestrator│\n└─────┘  └─────┘  └─────┘     └──────┬──────┘\n   │        │        │               │\n   ▼        ▼        ▼         ┌─────┼─────┐\n Event    Event    Event       ▼     ▼     ▼\n                            ┌────┐┌────┐┌────┐\n                            │Svc1││Svc2││Svc3│\n                            └────┘└────┘└────┘\n```\n\n### 2. Saga Execution States\n\n| State            | Description                    |\n| ---------------- | ------------------------------ |\n| **Started**      | Saga initiated                 |\n| **Pending**      | Waiting for step completion    |\n| **Compensating** | Rolling back due to failure    |\n| **Completed**    | All steps succeeded            |\n| **Failed**       | Saga failed after compensation |\n\n## Templates\n\n### Template 1: Saga Orchestrator Base\n\n```python\nfrom abc import ABC, abstractmethod\nfrom dataclasses import dataclass, field\nfrom enum import Enum\nfrom typing import List, Dict, Any, Optional\nfrom datetime import datetime\nimport uuid\n\nclass SagaState(Enum):\n    STARTED = \"started\"\n    PENDING = \"pending\"\n    COMPENSATING = \"compensating\"\n    COMPLETED = \"completed\"\n    FAILED = \"failed\"\n\n\n@dataclass\nclass SagaStep:\n    name: str\n    action: str\n    compensation: str\n    status: str = \"pending\"\n    result: Optional[Dict] = None\n    error: Optional[str] = None\n    executed_at: Optional[datetime] = None\n    compensated_at: Optional[datetime] = None\n\n\n@dataclass\nclass Saga:\n    saga_id: str\n    saga_type: str\n    state: SagaState\n    data: Dict[str, Any]\n    steps: List[SagaStep]\n    current_step: int = 0\n    created_at: datetime = field(default_factory=datetime.utcnow)\n    updated_at: datetime = field(default_factory=datetime.utcnow)\n\n\nclass SagaOrchestrator(ABC):\n    \"\"\"Base class for saga orchestrators.\"\"\"\n\n    def __init__(self, saga_store, event_publisher):\n        self.saga_store = saga_store\n        self.event_publisher = event_publisher\n\n    @abstractmethod\n    def define_steps(self, data: Dict) -> List[SagaStep]:\n        \"\"\"Define the saga steps.\"\"\"\n        pass\n\n    @property\n    @abstractmethod\n    def saga_type(self) -> str:\n        \"\"\"Unique saga type identifier.\"\"\"\n        pass\n\n    async def start(self, data: Dict) -> Saga:\n        \"\"\"Start a new saga.\"\"\"\n        saga = Saga(\n            saga_id=str(uuid.uuid4()),\n            saga_type=self.saga_type,\n            state=SagaState.STARTED,\n            data=data,\n            steps=self.define_steps(data)\n        )\n        await self.saga_store.save(saga)\n        await self._execute_next_step(saga)\n        return saga\n\n    async def handle_step_completed(self, saga_id: str, step_name: str, result: Dict):\n        \"\"\"Handle successful step completion.\"\"\"\n        saga = await self.saga_store.get(saga_id)\n\n        # Update step\n        for step in saga.steps:\n            if step.name == step_name:\n                step.status = \"completed\"\n                step.result = result\n                step.executed_at = datetime.utcnow()\n                break\n\n        saga.current_step += 1\n        saga.updated_at = datetime.utcnow()\n\n        # Check if saga is complete\n        if saga.current_step >= len(saga.steps):\n            saga.state = SagaState.COMPLETED\n            await self.saga_store.save(saga)\n            await self._on_saga_completed(saga)\n        else:\n            saga.state = SagaState.PENDING\n            await self.saga_store.save(saga)\n            await self._execute_next_step(saga)\n\n    async def handle_step_failed(self, saga_id: str, step_name: str, error: str):\n        \"\"\"Handle step failure - start compensation.\"\"\"\n        saga = await self.saga_store.get(saga_id)\n\n        # Mark step as failed\n        for step in saga.steps:\n            if step.name == step_name:\n                step.status = \"failed\"\n                step.error = error\n                break\n\n        saga.state = SagaState.COMPENSATING\n        saga.updated_at = datetime.utcnow()\n        await self.saga_store.save(saga)\n\n        # Start compensation from current step backwards\n        await self._compensate(saga)\n\n    async def _execute_next_step(self, saga: Saga):\n        \"\"\"Execute the next step in the saga.\"\"\"\n        if saga.current_step >= len(saga.steps):\n            return\n\n        step = saga.steps[saga.current_step]\n        step.status = \"executing\"\n        await self.saga_store.save(saga)\n\n        # Publish command to execute step\n        await self.event_publisher.publish(\n            step.action,\n            {\n                \"saga_id\": saga.saga_id,\n                \"step_name\": step.name,\n                **saga.data\n            }\n        )\n\n    async def _compensate(self, saga: Saga):\n        \"\"\"Execute compensation for completed steps.\"\"\"\n        # Compensate in reverse order\n        for i in range(saga.current_step - 1, -1, -1):\n            step = saga.steps[i]\n            if step.status == \"completed\":\n                step.status = \"compensating\"\n                await self.saga_store.save(saga)\n\n                await self.event_publisher.publish(\n                    step.compensation,\n                    {\n                        \"saga_id\": saga.saga_id,\n                        \"step_name\": step.name,\n                        \"original_result\": step.result,\n                        **saga.data\n                    }\n                )\n\n    async def handle_compensation_completed(self, saga_id: str, step_name: str):\n        \"\"\"Handle compensation completion.\"\"\"\n        saga = await self.saga_store.get(saga_id)\n\n        for step in saga.steps:\n            if step.name == step_name:\n                step.status = \"compensated\"\n                step.compensated_at = datetime.utcnow()\n                break\n\n        # Check if all compensations complete\n        all_compensated = all(\n            s.status in (\"compensated\", \"pending\", \"failed\")\n            for s in saga.steps\n        )\n\n        if all_compensated:\n            saga.state = SagaState.FAILED\n            await self._on_saga_failed(saga)\n\n        await self.saga_store.save(saga)\n\n    async def _on_saga_completed(self, saga: Saga):\n        \"\"\"Called when saga completes successfully.\"\"\"\n        await self.event_publisher.publish(\n            f\"{self.saga_type}Completed\",\n            {\"saga_id\": saga.saga_id, **saga.data}\n        )\n\n    async def _on_saga_failed(self, saga: Saga):\n        \"\"\"Called when saga fails after compensation.\"\"\"\n        await self.event_publisher.publish(\n            f\"{self.saga_type}Failed\",\n            {\"saga_id\": saga.saga_id, \"error\": \"Saga failed\", **saga.data}\n        )\n```\n\n### Template 2: Order Fulfillment Saga\n\n```python\nclass OrderFulfillmentSaga(SagaOrchestrator):\n    \"\"\"Orchestrates order fulfillment across services.\"\"\"\n\n    @property\n    def saga_type(self) -> str:\n        return \"OrderFulfillment\"\n\n    def define_steps(self, data: Dict) -> List[SagaStep]:\n        return [\n            SagaStep(\n                name=\"reserve_inventory\",\n                action=\"InventoryService.ReserveItems\",\n                compensation=\"InventoryService.ReleaseReservation\"\n            ),\n            SagaStep(\n                name=\"process_payment\",\n                action=\"PaymentService.ProcessPayment\",\n                compensation=\"PaymentService.RefundPayment\"\n            ),\n            SagaStep(\n                name=\"create_shipment\",\n                action=\"ShippingService.CreateShipment\",\n                compensation=\"ShippingService.CancelShipment\"\n            ),\n            SagaStep(\n                name=\"send_confirmation\",\n                action=\"NotificationService.SendOrderConfirmation\",\n                compensation=\"NotificationService.SendCancellationNotice\"\n            )\n        ]\n\n\n# Usage\nasync def create_order(order_data: Dict):\n    saga = OrderFulfillmentSaga(saga_store, event_publisher)\n    return await saga.start({\n        \"order_id\": order_data[\"order_id\"],\n        \"customer_id\": order_data[\"customer_id\"],\n        \"items\": order_data[\"items\"],\n        \"payment_method\": order_data[\"payment_method\"],\n        \"shipping_address\": order_data[\"shipping_address\"]\n    })\n\n\n# Event handlers in each service\nclass InventoryService:\n    async def handle_reserve_items(self, command: Dict):\n        try:\n            # Reserve inventory\n            reservation = await self.reserve(\n                command[\"items\"],\n                command[\"order_id\"]\n            )\n            # Report success\n            await self.event_publisher.publish(\n                \"SagaStepCompleted\",\n                {\n                    \"saga_id\": command[\"saga_id\"],\n                    \"step_name\": \"reserve_inventory\",\n                    \"result\": {\"reservation_id\": reservation.id}\n                }\n            )\n        except InsufficientInventoryError as e:\n            await self.event_publisher.publish(\n                \"SagaStepFailed\",\n                {\n                    \"saga_id\": command[\"saga_id\"],\n                    \"step_name\": \"reserve_inventory\",\n                    \"error\": str(e)\n                }\n            )\n\n    async def handle_release_reservation(self, command: Dict):\n        # Compensating action\n        await self.release_reservation(\n            command[\"original_result\"][\"reservation_id\"]\n        )\n        await self.event_publisher.publish(\n            \"SagaCompensationCompleted\",\n            {\n                \"saga_id\": command[\"saga_id\"],\n                \"step_name\": \"reserve_inventory\"\n            }\n        )\n```\n\n### Template 3: Choreography-Based Saga\n\n```python\nfrom dataclasses import dataclass\nfrom typing import Dict, Any\nimport asyncio\n\n@dataclass\nclass SagaContext:\n    \"\"\"Passed through choreographed saga events.\"\"\"\n    saga_id: str\n    step: int\n    data: Dict[str, Any]\n    completed_steps: list\n\n\nclass OrderChoreographySaga:\n    \"\"\"Choreography-based saga using events.\"\"\"\n\n    def __init__(self, event_bus):\n        self.event_bus = event_bus\n        self._register_handlers()\n\n    def _register_handlers(self):\n        self.event_bus.subscribe(\"OrderCreated\", self._on_order_created)\n        self.event_bus.subscribe(\"InventoryReserved\", self._on_inventory_reserved)\n        self.event_bus.subscribe(\"PaymentProcessed\", self._on_payment_processed)\n        self.event_bus.subscribe(\"ShipmentCreated\", self._on_shipment_created)\n\n        # Compensation handlers\n        self.event_bus.subscribe(\"PaymentFailed\", self._on_payment_failed)\n        self.event_bus.subscribe(\"ShipmentFailed\", self._on_shipment_failed)\n\n    async def _on_order_created(self, event: Dict):\n        \"\"\"Step 1: Order created, reserve inventory.\"\"\"\n        await self.event_bus.publish(\"ReserveInventory\", {\n            \"saga_id\": event[\"order_id\"],\n            \"order_id\": event[\"order_id\"],\n            \"items\": event[\"items\"]\n        })\n\n    async def _on_inventory_reserved(self, event: Dict):\n        \"\"\"Step 2: Inventory reserved, process payment.\"\"\"\n        await self.event_bus.publish(\"ProcessPayment\", {\n            \"saga_id\": event[\"saga_id\"],\n            \"order_id\": event[\"order_id\"],\n            \"amount\": event[\"total_amount\"],\n            \"reservation_id\": event[\"reservation_id\"]\n        })\n\n    async def _on_payment_processed(self, event: Dict):\n        \"\"\"Step 3: Payment done, create shipment.\"\"\"\n        await self.event_bus.publish(\"CreateShipment\", {\n            \"saga_id\": event[\"saga_id\"],\n            \"order_id\": event[\"order_id\"],\n            \"payment_id\": event[\"payment_id\"]\n        })\n\n    async def _on_shipment_created(self, event: Dict):\n        \"\"\"Step 4: Complete - send confirmation.\"\"\"\n        await self.event_bus.publish(\"OrderFulfilled\", {\n            \"saga_id\": event[\"saga_id\"],\n            \"order_id\": event[\"order_id\"],\n            \"tracking_number\": event[\"tracking_number\"]\n        })\n\n    # Compensation handlers\n    async def _on_payment_failed(self, event: Dict):\n        \"\"\"Payment failed - release inventory.\"\"\"\n        await self.event_bus.publish(\"ReleaseInventory\", {\n            \"saga_id\": event[\"saga_id\"],\n            \"reservation_id\": event[\"reservation_id\"]\n        })\n        await self.event_bus.publish(\"OrderFailed\", {\n            \"order_id\": event[\"order_id\"],\n            \"reason\": \"Payment failed\"\n        })\n\n    async def _on_shipment_failed(self, event: Dict):\n        \"\"\"Shipment failed - refund payment and release inventory.\"\"\"\n        await self.event_bus.publish(\"RefundPayment\", {\n            \"saga_id\": event[\"saga_id\"],\n            \"payment_id\": event[\"payment_id\"]\n        })\n        await self.event_bus.publish(\"ReleaseInventory\", {\n            \"saga_id\": event[\"saga_id\"],\n            \"reservation_id\": event[\"reservation_id\"]\n        })\n```\n\n### Template 4: Saga with Timeouts\n\n```python\nclass TimeoutSagaOrchestrator(SagaOrchestrator):\n    \"\"\"Saga orchestrator with step timeouts.\"\"\"\n\n    def __init__(self, saga_store, event_publisher, scheduler):\n        super().__init__(saga_store, event_publisher)\n        self.scheduler = scheduler\n\n    async def _execute_next_step(self, saga: Saga):\n        if saga.current_step >= len(saga.steps):\n            return\n\n        step = saga.steps[saga.current_step]\n        step.status = \"executing\"\n        step.timeout_at = datetime.utcnow() + timedelta(minutes=5)\n        await self.saga_store.save(saga)\n\n        # Schedule timeout check\n        await self.scheduler.schedule(\n            f\"saga_timeout_{saga.saga_id}_{step.name}\",\n            self._check_timeout,\n            {\"saga_id\": saga.saga_id, \"step_name\": step.name},\n            run_at=step.timeout_at\n        )\n\n        await self.event_publisher.publish(\n            step.action,\n            {\"saga_id\": saga.saga_id, \"step_name\": step.name, **saga.data}\n        )\n\n    async def _check_timeout(self, data: Dict):\n        \"\"\"Check if step has timed out.\"\"\"\n        saga = await self.saga_store.get(data[\"saga_id\"])\n        step = next(s for s in saga.steps if s.name == data[\"step_name\"])\n\n        if step.status == \"executing\":\n            # Step timed out - fail it\n            await self.handle_step_failed(\n                data[\"saga_id\"],\n                data[\"step_name\"],\n                \"Step timed out\"\n            )\n```\n\n## Durable Execution Alternative\n\nThe templates above build saga infrastructure from scratch — saga stores, event publishers, compensation tracking. **Durable execution frameworks** (like DBOS) eliminate much of this boilerplate: the workflow runtime automatically persists state to a database, retries failed steps, and resumes from the last checkpoint after crashes. Instead of building a `SagaOrchestrator` base class, you write a workflow function with steps — the framework handles persistence, crash recovery, and exactly-once execution semantics. Consider durable execution when you want saga-like reliability without managing the coordination infrastructure yourself.\n\n## Best Practices\n\n### Do's\n\n- **Make steps idempotent** - Safe to retry\n- **Design compensations carefully** - They must work\n- **Use correlation IDs** - For tracing across services\n- **Implement timeouts** - Don't wait forever\n- **Log everything** - For debugging failures\n\n### Don'ts\n\n- **Don't assume instant completion** - Sagas take time\n- **Don't skip compensation testing** - Most critical part\n- **Don't couple services** - Use async messaging\n- **Don't ignore partial failures** - Handle gracefully\n\n## Related Skills\n\nWorks well with: `event-sourcing-architect`, `workflow-automation`, `dbos-*`\n\n## Resources\n\n- [Saga Pattern](https:\u002F\u002Fmicroservices.io\u002Fpatterns\u002Fdata\u002Fsaga.html)\n- [Designing Data-Intensive Applications](https:\u002F\u002Fdataintensive.net\u002F)\n","# Saga Orchestration\n\nPatterns for managing distributed transactions and long-running business processes.\n\n## Do not use this skill when\n\n- The task is unrelated to saga orchestration\n- You need a different domain or tool outside this scope\n\n## Instructions\n\n- Clarify goals, constraints, and required inputs.\n- Apply relevant best practices and validate outcomes.\n- Provide actionable steps and verification.\n- If detailed examples are required, open `resources\u002Fimplementation-playbook.md`.\n\n## Use this skill when\n\n- Coordinating multi-service transactions\n- Implementing compensating transactions\n- Managing long-running business workflows\n- Handling failures in distributed systems\n- Building order fulfillment processes\n- Implementing approval workflows\n\n## Core Concepts\n\n### 1. Saga Types\n\n```\nChoreography                    Orchestration\n┌─────┐  ┌─────┐  ┌─────┐     ┌─────────────┐\n│Svc A│─►│Svc B│─►│Svc C│     │ Orchestrator│\n└─────┘  └─────┘  └─────┘     └──────┬──────┘\n   │        │        │               │\n   ▼        ▼        ▼         ┌─────┼─────┐\n Event    Event    Event       ▼     ▼     ▼\n                            ┌────┐┌────┐┌────┐\n                            │Svc1││Svc2││Svc3│\n                            └────┘└────┘└────┘\n```\n\n### 2. Saga Execution States\n\n| State            | Description                    |\n| ---------------- | ------------------------------ |\n| **Started**      | Saga initiated                 |\n| **Pending**      | Waiting for step completion    |\n| **Compensating** | Rolling back due to failure    |\n| **Completed**    | All steps succeeded            |\n| **Failed**       | Saga failed after compensation |\n\n## Templates\n\n### Template 1: Saga Orchestrator Base\n\n```python\nfrom abc import ABC, abstractmethod\nfrom dataclasses import dataclass, field\nfrom enum import Enum\nfrom typing import List, Dict, Any, Optional\nfrom datetime import datetime\nimport uuid\n\nclass SagaState(Enum):\n    STARTED = \"started\"\n    PENDING = \"pending\"\n    COMPENSATING = \"compensating\"\n    COMPLETED = \"completed\"\n    FAILED = \"failed\"\n\n\n@dataclass\nclass SagaStep:\n    name: str\n    action: str\n    compensation: str\n    status: str = \"pending\"\n    result: Optional[Dict] = None\n    error: Optional[str] = None\n    executed_at: Optional[datetime] = None\n    compensated_at: Optional[datetime] = None\n\n\n@dataclass\nclass Saga:\n    saga_id: str\n    saga_type: str\n    state: SagaState\n    data: Dict[str, Any]\n    steps: List[SagaStep]\n    current_step: int = 0\n    created_at: datetime = field(default_factory=datetime.utcnow)\n    updated_at: datetime = field(default_factory=datetime.utcnow)\n\n\nclass SagaOrchestrator(ABC):\n    \"\"\"Base class for saga orchestrators.\"\"\"\n\n    def __init__(self, saga_store, event_publisher):\n        self.saga_store = saga_store\n        self.event_publisher = event_publisher\n\n    @abstractmethod\n    def define_steps(self, data: Dict) -> List[SagaStep]:\n        \"\"\"Define the saga steps.\"\"\"\n        pass\n\n    @property\n    @abstractmethod\n    def saga_type(self) -> str:\n        \"\"\"Unique saga type identifier.\"\"\"\n        pass\n\n    async def start(self, data: Dict) -> Saga:\n        \"\"\"Start a new saga.\"\"\"\n        saga = Saga(\n            saga_id=str(uuid.uuid4()),\n            saga_type=self.saga_type,\n            state=SagaState.STARTED,\n            data=data,\n            steps=self.define_steps(data)\n        )\n        await self.saga_store.save(saga)\n        await self._execute_next_step(saga)\n        return saga\n\n    async def handle_step_completed(self, saga_id: str, step_name: str, result: Dict):\n        \"\"\"Handle successful step completion.\"\"\"\n        saga = await self.saga_store.get(saga_id)\n\n        # Update step\n        for step in saga.steps:\n            if step.name == step_name:\n                step.status = \"completed\"\n                step.result = result\n                step.executed_at = datetime.utcnow()\n                break\n\n        saga.current_step += 1\n        saga.updated_at = datetime.utcnow()\n\n        # Check if saga is complete\n        if saga.current_step >= len(saga.steps):\n            saga.state = SagaState.COMPLETED\n            await self.saga_store.save(saga)\n            await self._on_saga_completed(saga)\n        else:\n            saga.state = SagaState.PENDING\n            await self.saga_store.save(saga)\n            await self._execute_next_step(saga)\n\n    async def handle_step_failed(self, saga_id: str, step_name: str, error: str):\n        \"\"\"Handle step failure - start compensation.\"\"\"\n        saga = await self.saga_store.get(saga_id)\n\n        # Mark step as failed\n        for step in saga.steps:\n            if step.name == step_name:\n                step.status = \"failed\"\n                step.error = error\n                break\n\n        saga.state = SagaState.COMPENSATING\n        saga.updated_at = datetime.utcnow()\n        await self.saga_store.save(saga)\n\n        # Start compensation from current step backwards\n        await self._compensate(saga)\n\n    async def _execute_next_step(self, saga: Saga):\n        \"\"\"Execute the next step in the saga.\"\"\"\n        if saga.current_step >= len(saga.steps):\n            return\n\n        step = saga.steps[saga.current_step]\n        step.status = \"executing\"\n        await self.saga_store.save(saga)\n\n        # Publish command to execute step\n        await self.event_publisher.publish(\n            step.action,\n            {\n                \"saga_id\": saga.saga_id,\n                \"step_name\": step.name,\n                **saga.data\n            }\n        )\n\n    async def _compensate(self, saga: Saga):\n        \"\"\"Execute compensation for completed steps.\"\"\"\n        # Compensate in reverse order\n        for i in range(saga.current_step - 1, -1, -1):\n            step = saga.steps[i]\n            if step.status == \"completed\":\n                step.status = \"compensating\"\n                await self.saga_store.save(saga)\n\n                await self.event_publisher.publish(\n                    step.compensation,\n                    {\n                        \"saga_id\": saga.saga_id,\n                        \"step_name\": step.name,\n                        \"original_result\": step.result,\n                        **saga.data\n                    }\n                )\n\n    async def handle_compensation_completed(self, saga_id: str, step_name: str):\n        \"\"\"Handle compensation completion.\"\"\"\n        saga = await self.saga_store.get(saga_id)\n\n        for step in saga.steps:\n            if step.name == step_name:\n                step.status = \"compensated\"\n                step.compensated_at = datetime.utcnow()\n                break\n\n        # Check if all compensations complete\n        all_compensated = all(\n            s.status in (\"compensated\", \"pending\", \"failed\")\n            for s in saga.steps\n        )\n\n        if all_compensated:\n            saga.state = SagaState.FAILED\n            await self._on_saga_failed(saga)\n\n        await self.saga_store.save(saga)\n\n    async def _on_saga_completed(self, saga: Saga):\n        \"\"\"Called when saga completes successfully.\"\"\"\n        await self.event_publisher.publish(\n            f\"{self.saga_type}Completed\",\n            {\"saga_id\": saga.saga_id, **saga.data}\n        )\n\n    async def _on_saga_failed(self, saga: Saga):\n        \"\"\"Called when saga fails after compensation.\"\"\"\n        await self.event_publisher.publish(\n            f\"{self.saga_type}Failed\",\n            {\"saga_id\": saga.saga_id, \"error\": \"Saga failed\", **saga.data}\n        )\n```\n\n### Template 2: Order Fulfillment Saga\n\n```python\nclass OrderFulfillmentSaga(SagaOrchestrator):\n    \"\"\"Orchestrates order fulfillment across services.\"\"\"\n\n    @property\n    def saga_type(self) -> str:\n        return \"OrderFulfillment\"\n\n    def define_steps(self, data: Dict) -> List[SagaStep]:\n        return [\n            SagaStep(\n                name=\"reserve_inventory\",\n                action=\"InventoryService.ReserveItems\",\n                compensation=\"InventoryService.ReleaseReservation\"\n            ),\n            SagaStep(\n                name=\"process_payment\",\n                action=\"PaymentService.ProcessPayment\",\n                compensation=\"PaymentService.RefundPayment\"\n            ),\n            SagaStep(\n                name=\"create_shipment\",\n                action=\"ShippingService.CreateShipment\",\n                compensation=\"ShippingService.CancelShipment\"\n            ),\n            SagaStep(\n                name=\"send_confirmation\",\n                action=\"NotificationService.SendOrderConfirmation\",\n                compensation=\"NotificationService.SendCancellationNotice\"\n            )\n        ]\n\n\n# Usage\nasync def create_order(order_data: Dict):\n    saga = OrderFulfillmentSaga(saga_store, event_publisher)\n    return await saga.start({\n        \"order_id\": order_data[\"order_id\"],\n        \"customer_id\": order_data[\"customer_id\"],\n        \"items\": order_data[\"items\"],\n        \"payment_method\": order_data[\"payment_method\"],\n        \"shipping_address\": order_data[\"shipping_address\"]\n    })\n\n\n# Event handlers in each service\nclass InventoryService:\n    async def handle_reserve_items(self, command: Dict):\n        try:\n            # Reserve inventory\n            reservation = await self.reserve(\n                command[\"items\"],\n                command[\"order_id\"]\n            )\n            # Report success\n            await self.event_publisher.publish(\n                \"SagaStepCompleted\",\n                {\n                    \"saga_id\": command[\"saga_id\"],\n                    \"step_name\": \"reserve_inventory\",\n                    \"result\": {\"reservation_id\": reservation.id}\n                }\n            )\n        except InsufficientInventoryError as e:\n            await self.event_publisher.publish(\n                \"SagaStepFailed\",\n                {\n                    \"saga_id\": command[\"saga_id\"],\n                    \"step_name\": \"reserve_inventory\",\n                    \"error\": str(e)\n                }\n            )\n\n    async def handle_release_reservation(self, command: Dict):\n        # Compensating action\n        await self.release_reservation(\n            command[\"original_result\"][\"reservation_id\"]\n        )\n        await self.event_publisher.publish(\n            \"SagaCompensationCompleted\",\n            {\n                \"saga_id\": command[\"saga_id\"],\n                \"step_name\": \"reserve_inventory\"\n            }\n        )\n```\n\n### Template 3: Choreography-Based Saga\n\n```python\nfrom dataclasses import dataclass\nfrom typing import Dict, Any\nimport asyncio\n\n@dataclass\nclass SagaContext:\n    \"\"\"Passed through choreographed saga events.\"\"\"\n    saga_id: str\n    step: int\n    data: Dict[str, Any]\n    completed_steps: list\n\n\nclass OrderChoreographySaga:\n    \"\"\"Choreography-based saga using events.\"\"\"\n\n    def __init__(self, event_bus):\n        self.event_bus = event_bus\n        self._register_handlers()\n\n    def _register_handlers(self):\n        self.event_bus.subscribe(\"OrderCreated\", self._on_order_created)\n        self.event_bus.subscribe(\"InventoryReserved\", self._on_inventory_reserved)\n        self.event_bus.subscribe(\"PaymentProcessed\", self._on_payment_processed)\n        self.event_bus.subscribe(\"ShipmentCreated\", self._on_shipment_created)\n\n        # Compensation handlers\n        self.event_bus.subscribe(\"PaymentFailed\", self._on_payment_failed)\n        self.event_bus.subscribe(\"ShipmentFailed\", self._on_shipment_failed)\n\n    async def _on_order_created(self, event: Dict):\n        \"\"\"Step 1: Order created, reserve inventory.\"\"\"\n        await self.event_bus.publish(\"ReserveInventory\", {\n            \"saga_id\": event[\"order_id\"],\n            \"order_id\": event[\"order_id\"],\n            \"items\": event[\"items\"]\n        })\n\n    async def _on_inventory_reserved(self, event: Dict):\n        \"\"\"Step 2: Inventory reserved, process payment.\"\"\"\n        await self.event_bus.publish(\"ProcessPayment\", {\n            \"saga_id\": event[\"saga_id\"],\n            \"order_id\": event[\"order_id\"],\n            \"amount\": event[\"total_amount\"],\n            \"reservation_id\": event[\"reservation_id\"]\n        })\n\n    async def _on_payment_processed(self, event: Dict):\n        \"\"\"Step 3: Payment done, create shipment.\"\"\"\n        await self.event_bus.publish(\"CreateShipment\", {\n            \"saga_id\": event[\"saga_id\"],\n            \"order_id\": event[\"order_id\"],\n            \"payment_id\": event[\"payment_id\"]\n        })\n\n    async def _on_shipment_created(self, event: Dict):\n        \"\"\"Step 4: Complete - send confirmation.\"\"\"\n        await self.event_bus.publish(\"OrderFulfilled\", {\n            \"saga_id\": event[\"saga_id\"],\n            \"order_id\": event[\"order_id\"],\n            \"tracking_number\": event[\"tracking_number\"]\n        })\n\n    # Compensation handlers\n    async def _on_payment_failed(self, event: Dict):\n        \"\"\"Payment failed - release inventory.\"\"\"\n        await self.event_bus.publish(\"ReleaseInventory\", {\n            \"saga_id\": event[\"saga_id\"],\n            \"reservation_id\": event[\"reservation_id\"]\n        })\n        await self.event_bus.publish(\"OrderFailed\", {\n            \"order_id\": event[\"order_id\"],\n            \"reason\": \"Payment failed\"\n        })\n\n    async def _on_shipment_failed(self, event: Dict):\n        \"\"\"Shipment failed - refund payment and release inventory.\"\"\"\n        await self.event_bus.publish(\"RefundPayment\", {\n            \"saga_id\": event[\"saga_id\"],\n            \"payment_id\": event[\"payment_id\"]\n        })\n        await self.event_bus.publish(\"ReleaseInventory\", {\n            \"saga_id\": event[\"saga_id\"],\n            \"reservation_id\": event[\"reservation_id\"]\n        })\n```\n\n### Template 4: Saga with Timeouts\n\n```python\nclass TimeoutSagaOrchestrator(SagaOrchestrator):\n    \"\"\"Saga orchestrator with step timeouts.\"\"\"\n\n    def __init__(self, saga_store, event_publisher, scheduler):\n        super().__init__(saga_store, event_publisher)\n        self.scheduler = scheduler\n\n    async def _execute_next_step(self, saga: Saga):\n        if saga.current_step >= len(saga.steps):\n            return\n\n        step = saga.steps[saga.current_step]\n        step.status = \"executing\"\n        step.timeout_at = datetime.utcnow() + timedelta(minutes=5)\n        await self.saga_store.save(saga)\n\n        # Schedule timeout check\n        await self.scheduler.schedule(\n            f\"saga_timeout_{saga.saga_id}_{step.name}\",\n            self._check_timeout,\n            {\"saga_id\": saga.saga_id, \"step_name\": step.name},\n            run_at=step.timeout_at\n        )\n\n        await self.event_publisher.publish(\n            step.action,\n            {\"saga_id\": saga.saga_id, \"step_name\": step.name, **saga.data}\n        )\n\n    async def _check_timeout(self, data: Dict):\n        \"\"\"Check if step has timed out.\"\"\"\n        saga = await self.saga_store.get(data[\"saga_id\"])\n        step = next(s for s in saga.steps if s.name == data[\"step_name\"])\n\n        if step.status == \"executing\":\n            # Step timed out - fail it\n            await self.handle_step_failed(\n                data[\"saga_id\"],\n                data[\"step_name\"],\n                \"Step timed out\"\n            )\n```\n\n## Durable Execution Alternative\n\nThe templates above build saga infrastructure from scratch — saga stores, event publishers, compensation tracking. **Durable execution frameworks** (like DBOS) eliminate much of this boilerplate: the workflow runtime automatically persists state to a database, retries failed steps, and resumes from the last checkpoint after crashes. Instead of building a `SagaOrchestrator` base class, you write a workflow function with steps — the framework handles persistence, crash recovery, and exactly-once execution semantics. Consider durable execution when you want saga-like reliability without managing the coordination infrastructure yourself.\n\n## Best Practices\n\n### Do's\n\n- **Make steps idempotent** - Safe to retry\n- **Design compensations carefully** - They must work\n- **Use correlation IDs** - For tracing across services\n- **Implement timeouts** - Don't wait forever\n- **Log everything** - For debugging failures\n\n### Don'ts\n\n- **Don't assume instant completion** - Sagas take time\n- **Don't skip compensation testing** - Most critical part\n- **Don't couple services** - Use async messaging\n- **Don't ignore partial failures** - Handle gracefully\n\n## Related Skills\n\nWorks well with: `event-sourcing-architect`, `workflow-automation`, `dbos-*`\n\n## Resources\n\n- [Saga Pattern](https:\u002F\u002Fmicroservices.io\u002Fpatterns\u002Fdata\u002Fsaga.html)\n- [Designing Data-Intensive Applications](https:\u002F\u002Fdataintensive.net\u002F)\n",{"name":5,"risk":32,"source":25,"date_added":33,"description":7},"unknown","2026-02-27","main","a50a3aa6b39fb0e1b7db88bef1bfc9c93606e126","modules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fsaga-orchestration",0,"https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant","https:\u002F\u002Fgithub.com\u002FSam-06060","Mobile Application Developer | Kotlin | Flutter, KMP, Swfit, Android,Swift UI | Building at Saar It Resources | Creator of Jarvis (AI Assistant)","2026-06-23 05:13:38",{"source":8,"skillName":5,"commands":43,"prompt":53,"zipAvailable":54},[44,47,50],{"tool":45,"command":46},"npx","npx skills add Sam-06060\u002Fjarvis-assistant --skill saga-orchestration",{"tool":48,"command":49},"bunx","bunx skills add Sam-06060\u002Fjarvis-assistant --skill saga-orchestration",{"tool":51,"command":52},"pnpm","pnpm dlx skills add Sam-06060\u002Fjarvis-assistant --skill saga-orchestration","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fmodules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fsaga-orchestration\u002FSKILL.md",true,[56],{"path":57,"resourceType":58,"resourceTypeDesc":59,"sizeBytes":60,"sourceHtmlUrl":61},"resources\u002Fimplementation-playbook.md","REFERENCE","参考文档",859,"https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fmodules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fsaga-orchestration\u002Fresources\u002Fimplementation-playbook.md",[63,76,91,118,137,164],{"skillNo":64,"name":65,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":66,"categories":67,"keywords":73,"publishedAt":27},"01M6GDRVS6FXX3ESH0C9DW01C0","test_skill","https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fscratch\u002Ftest_skill\u002FSKILL.md",[68],{"categoryNo":69,"categoryName":70,"taxonomyType":71,"taxonomyTypeDesc":72},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",[74,75],"Test Skill","test",{"skillNo":77,"name":78,"nameZh":6,"description":79,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":80,"categories":81,"keywords":82,"publishedAt":27},"01M6GDRQ40HX22MA6XWC31RHHK","zustand-store-ts","Create Zustand stores following established patterns with proper TypeScript types and middleware.","https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fmodules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fzustand-store-ts\u002FSKILL.md",[],[83,84,85,86,87,88,26,25,89,90],"zustand store ts","zustand","store","with","types","middleware","create","typescript",{"skillNo":92,"name":93,"nameZh":6,"description":94,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":95,"categories":96,"keywords":100,"publishedAt":27},"01M6GDRKEA0WE670SPFWX5GKCN","zoom-automation","Automate Zoom meeting creation, management, recordings, webinars, and participant tracking via Rube MCP (Composio). Always search tools first for current schemas.","https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fmodules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fzoom-automation\u002FSKILL.md",[97],{"categoryNo":98,"categoryName":99,"taxonomyType":71,"taxonomyTypeDesc":72},"01JBSEEDCAT000000000000023","Skill与智能体开发",[101,102,103,104,105,106,107,108,109,110,111,112,113,114,25,115,116,117],"automation","zoom automation","zoom","first","Tools","search","MCP","via","meeting","automate","critical","creation","webinars","composio","recordings","management","tracking",{"skillNo":119,"name":120,"nameZh":6,"description":121,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":125,"publishedAt":27},"01M6GDRFS1452PC71JQ38S24HR","zoho-crm-automation","Automate Zoho CRM tasks via Rube MCP (Composio): create\u002Fupdate records, search contacts, manage leads, and convert leads. Always search tools first for current schemas.","https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fmodules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fzoho-crm-automation\u002FSKILL.md",[124],{"categoryNo":98,"categoryName":99,"taxonomyType":71,"taxonomyTypeDesc":72},[126,101,127,128,129,130,131,25,106,132,114,133,111,110,105,134,89,135,107,136],"crm automation","zoho crm","crm","zoho crm automation","zoho","leads","contacts","records","update","tasks","manage",{"skillNo":138,"name":139,"nameZh":6,"description":140,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":141,"categories":142,"keywords":146,"publishedAt":27},"01M6GDRCKQBAVTGHX5XBH26KPZ","zod-validation-expert","Expert in Zod — TypeScript-first schema validation. Covers parsing, custom errors, refinements, type inference, and integration with React Hook Form, Next.js, and tRPC.","https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fmodules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fzod-validation-expert\u002FSKILL.md",[143],{"categoryNo":144,"categoryName":145,"taxonomyType":71,"taxonomyTypeDesc":72},"01JBSEEDCAT000000000000009","前端开发",[147,148,149,150,151,90,152,153,154,155,156,157,86,158,159,160,161,25,162,163],"expert","zod","zod validation expert","validation","react","safe","parsing","errors","schema validation","react hook form","hook","trpc","form","type","next","schema","Next.js",{"skillNo":165,"name":166,"nameZh":6,"description":167,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":168,"categories":169,"keywords":171,"publishedAt":27},"01M6GDR658B08K4MY0RWD4A6EH","zeroize-audit","Detects missing zeroization of sensitive data in source code and identifies zeroization removed by compiler optimizations, with assembly-level analysis, and control-flow verification. Use for auditing C\u002FC++\u002FRust code handling secrets, keys, passwords, or other sensitive data.","https:\u002F\u002Fgithub.com\u002FSam-06060\u002Fjarvis-assistant\u002Fblob\u002Fmain\u002Fmodules\u002Fagent_skills\u002Fawesome-skills\u002Fplaybooks\u002Fzeroize-audit\u002FSKILL.md",[170],{"categoryNo":98,"categoryName":99,"taxonomyType":71,"taxonomyTypeDesc":72},[172,173,174,175,176,177,178,179,25,180,181,182,183,184,185,186,187,188,189,107],"zeroize audit","audit","write","passwords","get","project","c++","activate","assembly","read","Bash","secrets","analysis","data","flow","verification","code","rust"]