DEV Community

Axel
Axel

Posted on

Event-Driven AWS: Choreography Pattern in Action

Introduction

To continue the article from Event-Driven AWS: Implementing Choreography Pattern, the best approach is to practically implement the event flow we've discussed.

1. AWS EventBridge Setup

Create an Event Bus

You can create a dedicated Event Bus in EventBridge to handle all events related to your aircraft booking system.

aws events create-event-bus --name AircraftBookingBus
Enter fullscreen mode Exit fullscreen mode

Define EventBridge Rules

You will create rules that route events to the appropriate service targets (like Lambda functions, SQS queues, or Step Functions).

Example rule to listen for the BookingCreated event and route it to the Payment Service:

aws events put-rule 
    --name PaymentProcessingRule --event-bus-name AircraftBookingBus
    --event-pattern '{"source": ["aircraft.booking"], "detail-type": ["BookingCreated"]}'
Enter fullscreen mode Exit fullscreen mode

Example Event Patterns for EventBridge Rules

Rule for BookingCreatedRule (Target: Payment Service)

    {
      "source": ["aircraft.booking"],
      "detail-type": ["BookingCreated"]
    }
Enter fullscreen mode Exit fullscreen mode

Rule for PaymentConfirmedRule (Target: Seat Assignment Service)

    {
      "source": ["aircraft.payment"],
      "detail-type": ["PaymentConfirmed"]
    }
Enter fullscreen mode Exit fullscreen mode

Rule for TicketIssuedRule (Target: Ticket Service)

    {
      "source": ["aircraft.seat-assignment"],
      "detail-type": ["SeatAssigned"]
    }
Enter fullscreen mode Exit fullscreen mode

You can similarly create rules for PaymentConfirmed and SeatAssigned events, and route them to the corresponding services.

Set Targets for EventBridge Rules

After defining the rules, you need to specify which service (e.g., Lambda) should be triggered by each event.

Example: Route the BookingCreated event to a Lambda function that handles payment:

aws events put-targets --rule BookingCreatedRule --targets \\
    "Id"="1","Arn"="<Lambda-Payment-Service-ARN>"
Enter fullscreen mode Exit fullscreen mode

2. Services flow

Booking is Created

The Booking Service creates a booking and publishes an event called BookingCreated to EventBridge.

{
    "source": "aircraft.booking",
    "detail-type": "BookingCreated",
    "detail": {
        "bookingId": "B123",
        "customerId": "CUST001",
        "flightId": "FLIGHT001",
        "amount": 300
    }
}
Enter fullscreen mode Exit fullscreen mode

The EventBridge BookingCreatedRule has a rule that listens for BookingCreated events where the source is aircraft.booking.

Payment Service Receives BookingCreated

Upon receiving the event, the Payment Service processes the payment and publishes either a PaymentConfirmed or PaymentFailed event based on the outcome.

{
    "source": "aircraft.payment",
    "detail-type": "PaymentConfirmed",
    "detail": {
        "status": "SUCCESS",
        "bookingId": "B123",
        "customerId": "CUST001",
        "paymentId": "PAY001"
    }
}
Enter fullscreen mode Exit fullscreen mode

Seat Assignment Service Receives PaymentConfirmed

The Seat Assignment Service listens for the PaymentConfirmed event as well. When a new booking is created, it assigns a seat to the customer and publishes a SeatAssigned event.

SeatAssigned event

{
    "source": "aircraft.seat-assignment",
    "detail-type": "SeatAssigned",
    "detail": {
        "bookingId": "B123",
        "customerId": "CUST001",
        "seat": "12A"
    }
}
Enter fullscreen mode Exit fullscreen mode

3. Create Lambda Functions for Each Service

Create the necessary Lambda functions (or use SQS, Step Functions, etc.) to handle events for each service, such as Payment, Seat Assignment, Ticket, and Notifications.

Here is an example in python for Seat Assignment Service :

import json
import boto3
from datetime import datetime

eventbridge = boto3.client('events')
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('PaymentTable')

def lambda_handler(event, context):
    payment_status = event['detail']['status']
    booking_id = event['detail']['bookingId']
    customer_id = event['detail']['customerId']
    flight_id = event['detail']['flightId']
    amount = event['detail']['amount']    

    if payment_status == 'SUCCESS':
        # Store information details in DynamoDB
        table.put_item(
            Item={
                'CustomerID': customer_id,
                'BookingID': booking_id,
                'flightID': flight_id,
                'Timestamp': str(datetime.now(datetime.timezone.utc))
            }
        )

        # Publish event to EventBridge for next step (Ticket Service)
        eventbridge.put_events(
            Entries=[
                {
                    'Source': 'aircraft.seat-assignment',
                    'DetailType': 'SeatAssigned',
                    'Detail': json.dumps({'bookingId': booking_id, 'customerId': customer_id, 'seat': '12A'}),
                    'EventBusName': 'AircraftBookingBus'
                }
            ]
        )
        print(f"Seat Assigmed for {customer_id}. Stored in DynamoDB and event sent.")
    else:
        print(f"Seat Assigmed failed for {customer_id}.")

    return {
        'statusCode': 200,
        'body': json.dumps('Payment Lambda executed successfully')
    }
Enter fullscreen mode Exit fullscreen mode

Conclusion

In conclusion, the implementation of the AWS event-driven choreography pattern enables seamless integration and coordination between microservices using events. By leveraging services like EventBridge and Lambda functions, various components like booking, payment, and seat assignment services can operate asynchronously, improving scalability and decoupling. This architecture is highly flexible and supports business processes efficiently while ensuring that each service reacts to specific events without requiring direct interactions, enhancing the overall system's maintainability and robustness.

Top comments (0)