Hone logo
Hone
Problems

Distributed Transaction Management with the Saga Pattern

The Saga pattern is a crucial technique for managing distributed transactions across multiple microservices. It allows you to maintain data consistency in a system where a single atomic transaction isn't possible. This challenge asks you to implement a simplified version of the Saga pattern in Python to orchestrate a series of operations across different services.

Problem Description

You are tasked with implementing a Saga pattern to manage a simplified order processing workflow. The workflow involves two services: a PaymentService and an InventoryService. The Saga should attempt to process an order by first charging the customer's payment and then updating the inventory. If either operation fails, the Saga must execute compensating transactions to undo the previous operations, ensuring eventual consistency.

What needs to be achieved:

  • Create a Saga class that orchestrates the order processing workflow.
  • Implement PaymentService and InventoryService classes with methods for charging payment and updating inventory respectively. These services should simulate success or failure with a configurable probability.
  • Implement compensating transactions for both services: refund_payment and restore_inventory.
  • The Saga should handle failures gracefully by executing compensating transactions in reverse order of the original operations.

Key Requirements:

  • The Saga should accept an order ID and customer details.
  • The Saga should attempt to charge the payment using the PaymentService.
  • If the payment is successful, the Saga should attempt to update the inventory using the InventoryService.
  • If either operation fails, the Saga should execute the necessary compensating transactions.
  • The Saga should return a status indicating success or failure, along with any error messages.

Expected Behavior:

  • Success: If both payment and inventory operations succeed, the Saga should return a success status.
  • Payment Failure: If the payment fails, the Saga should return a failure status and an error message indicating the payment failure.
  • Inventory Failure (after successful payment): If the inventory update fails after a successful payment, the Saga should refund the payment and return a failure status with an error message indicating the inventory failure.
  • Compensating Transaction Failure: If a compensating transaction fails, the Saga should log the error and continue attempting to execute subsequent compensating transactions. The final status should reflect the overall failure.

Edge Cases to Consider:

  • Simulate service failures with a configurable probability to test the Saga's fault tolerance.
  • Handle potential exceptions during service calls and compensating transactions.
  • Consider how to handle scenarios where a service might be unavailable. (For simplicity, assume retries are not required in this challenge).

Examples

Example 1:

Input: order_id="123", customer_id="456", payment_amount=100.00, payment_success_probability=0.8, inventory_success_probability=0.7
Output: {"status": "success", "message": "Order processed successfully."}
Explanation: The payment succeeds (80% probability), the inventory update succeeds (70% probability), and the Saga completes successfully.

Example 2:

Input: order_id="456", customer_id="789", payment_amount=50.00, payment_success_probability=0.2, inventory_success_probability=0.9
Output: {"status": "failure", "message": "Payment failed."}
Explanation: The payment fails (20% probability), and the Saga immediately returns a failure status.

Example 3:

Input: order_id="789", customer_id="101", payment_amount=25.00, payment_success_probability=0.9, inventory_success_probability=0.3
Output: {"status": "failure", "message": "Inventory update failed. Refunding payment."}
Explanation: The payment succeeds (90% probability), but the inventory update fails (30% probability). The Saga refunds the payment and returns a failure status.

Constraints

  • payment_success_probability and inventory_success_probability should be floats between 0.0 and 1.0.
  • The Saga should handle exceptions gracefully and log errors.
  • The code should be well-structured and readable.
  • The solution should be implementable within a reasonable timeframe (e.g., 2-3 hours).
  • No external libraries beyond standard Python libraries are allowed.

Notes

  • This is a simplified implementation of the Saga pattern. Real-world implementations often involve more complex considerations like idempotency, distributed logging, and transaction isolation.
  • Focus on demonstrating the core concepts of the Saga pattern: sequential operations and compensating transactions.
  • Consider using a dictionary to represent the Saga's state.
  • Think about how to handle potential errors during compensating transactions. Logging is crucial.
  • The success/failure probabilities are meant to simulate real-world service unreliability. Use them to test your Saga's resilience.
Loading editor...
python