Testing Events Archive and Replay with LocalStack & EventBridge

EventBridge allows you to manage events across different AWS services and applications. Event sources for EventBridge can include a vast array of AWS services that are natively integrated, third-party applications through integrations, or custom applications. Similarly, events can be directed to numerous AWS services or custom applications via API endpoints.

EventBridge buses, as per design, are transient carriers for events, making them a black box which event-driven systems often are. This makes it difficult to track what event came through and where it went. This can be partially mitigated by using archives, wherein you can configure a rule on your event bus to automatically save all incoming events to an archive. The replay feature then lets you replay all stored events on the event bus.

LocalStack allows you to emulate and test this archive and replay workflow on your local machine. In this tutorial, you'll create a Lambda function locally using LocalStack & AWS CLI to serve as the target for an EventBridge rule. You will then create an archive, and once events are stored in the archive, you will replay them.

Prerequisites

Start your LocalStack container

Launch the LocalStack container on your local machine using the specified command:

PROVIDER_OVERRIDE_EVENTS=v2 localstack start

The configuration variable PROVIDER_OVERRIDE_EVENTS=v2 enables you to set the EventBridge v2 provider, which enhances emulation for EventBridge features like buses, rules, patterns, and targets, and supports archive & replay.

Once initiated, you'll receive a confirmation output indicating that the LocalStack container is up and running.


     __                     _______ __             __
    / /   ____  _________ _/ / ___// /_____ ______/ /__
   / /   / __ \/ ___/ __ `/ /\__ \/ __/ __ `/ ___/ //_/
  / /___/ /_/ / /__/ /_/ / /___/ / /_/ /_/ / /__/ ,<
 /_____/\____/\___/\__,_/_//____/\__/\__,_/\___/_/|_|

 💻 LocalStack CLI 3.6.0
 👤 Profile: default

[20:19:34] starting LocalStack in    localstack.py:503
           Docker mode 🐳
...
LocalStack version: 3.6.1.dev20240725091954
LocalStack build date: 2024-07-26
LocalStack build git hash: d536652

Create a Lambda Function

Since the event bus is transient, you need a target to verify what events pass through your system. You can create a Lambda function to log the events.

To begin, create a new file named index.js. Add the following code to log events:

'use strict';

exports.handler = (event, context, callback) => {
    console.log('LogScheduledEvent');
    console.log('Received event:', JSON.stringify(event, null, 2));
    callback(null, 'Finished');
};

This code logs details of incoming events and concludes by sending a Finished message via the callback.

Next, package this file into a ZIP archive with the command:

zip function.zip index.js

Deploy the Lambda function using the following command:

awslocal lambda create-function \
    --function-name LogScheduledEvent \
    --runtime nodejs18.x \
    --role arn:aws:iam::000000000000:role/lambda-ex \
    --handler index.handler \
    --zip-file fileb://function.zip

The command outputs details about the function, including its name, pending state, and other configuration data:

{
    "FunctionName": "LogScheduledEvent",
    ...
    "State": "Pending",
    "StateReason": "The function is being created.",
    "StateReasonCode": "Creating",
    ...
    "EphemeralStorage": {
        "Size": 512
    },
    ...
    "RuntimeVersionConfig": {
        "RuntimeVersionArn": "arn:aws:lambda:us-east-1::runtime:8eeff65f6809a3ce81507fe733fe09b835899b99481ba22fd7
5b5a7338290ec1"
    }
}

Create an EventBridge Archive

You can set up an EventBridge archive to store past events. This archive can hold events indefinitely or for a specified number of days. When configuring the archive, you can either capture all events from an event bus or selectively store only targeted events. Additionally, you can apply filters or rules to store events that meet specific criteria.

To start, create a custom event bus named test-event-bus to receive events, using this command:

awslocal events create-event-bus --name test-event-bus

The output would confirm the creation of the event bus:

{
    "EventBusArn": "arn:aws:events:us-east-1:000000000000:event-bus/test-event-bus"
}

Create an EventBridge Rule

You can create a rule named ARTestRule to archive events that are sent to the event bus. EventBridge rules allow you to route specific events according to your needs. This rule filters events based on defined patterns and sends matching events to attached target services.

To create the rule, execute the following command:

awslocal events put-rule \
    --name ARTestRule \
    --event-bus-name test-event-bus \
    --event-pattern '{
      "detail-type": ["customerCreated"]
    }'

You should see the following output:

{
    "RuleArn": "arn:aws:events:us-east-1:000000000000:rule/test-event-bus/ARTestRule"
}

Create an EventBridge Target

You can then choose a target. Targets are entities that consume your events. When an event triggers a rule, all targets linked to that rule are activated.

In this case, you can use the Lambda function as the target by retrieving the ARN of the Lambda function:

awslocal lambda get-function \
    --function-name LogScheduledEvent \
    --query 'Configuration.FunctionArn' \
    --output text

The Lambda ARN output will be:

arn:aws:lambda:us-east-1:000000000000:function:LogScheduledEvent

Finally, you can associate the Lambda function as a target to the ARTestRule using this command:

awslocal events put-targets \
    --rule ARTestRule \
    --event-bus-name test-event-bus \
    --targets '[
      {
        "Id": "1",
        "Arn": "arn:aws:lambda:us-east-1:000000000000:function:LogScheduledEvent"
      }
    ]'

You should see the following output:

{
    "FailedEntryCount": 0,
    "FailedEntries": []
}

Create an EventBridge Archive

Next, establish an archive named ArchiveTest using the ARN from your event bus:

awslocal events create-archive \
    --archive-name ArchiveTest \
    --event-source-arn arn:aws:events:us-east-1:000000000000:event-bus/test-event-bus

The output would show the archive's ARN, its enabled state, and creation time:

{
    "ArchiveArn": "arn:aws:events:us-east-1:000000000000:archive/ArchiveTest",
    "State": "ENABLED",
    "CreationTime": "2024-08-03T19:03:00.917596+05:30"
}

Send a test event

With the archive and rule configured, you can send a test event to verify that the system is functioning as expected. Execute the following command to send a test event:

awslocal events put-events --entries '[
  {
    "Source": "TestEvent",
    "DetailType": "customerCreated",
    "Detail": "{}",
    "EventBusName": "test-event-bus"
  }
]'

In this command:

  • The event source is identified as TestEvent.

  • The event is sent to the test-event-bus.

  • The event detail is empty ({}) and the type is customerCreated.

The output should confirm successful event submission:

{
    "FailedEntryCount": 0,
    "Entries": [
        {
            "EventId": "ee947775-0dcd-405c-8ba9-e100dcf244fa"
        }
    ]
}

Replay the event

Once test events are stored in the archive, you can replay them. To replay events, you need to specify both the source and the event bus they should be replayed into. Events must be replayed into the same event bus from which they were collected. You can also define a specific time window during which you want the events to be replayed into the bus.

Run the following command to start the replay:

awslocal events start-replay \
    --replay-name ReplayTest \
    --event-source-arn arn:aws:events:us-east-1:000000000000:archive/ArchiveTest \
    --event-start-time 2024-08-01 --event-end-time 2024-08-06 \
    --destination '{"Arn":"arn:aws:events:us-east-1:000000000000:event-bus/test-event-bus"}'

In the above command:

  • The replay name is specified as ReplayTest.

  • The event source ARN is the archive's ARN.

  • The event start and end times are chosen based on the article's date but can be customized.

  • The destination is the ARN for the test-event-bus.

The output should look like this:

{
    "ReplayArn": "arn:aws:events:us-east-1:000000000000:replay/ReplayTest",
    "State": "COMPLETED",
    "ReplayStartTime": "2024-08-06T12:58:01.405559+05:30"
}

To further inspect the replay details, use the command:

awslocal events describe-replay --replay-name ReplayTest

The description output will provide detailed information about the replay:

{
    "ReplayName": "ReplayTest",
    "ReplayArn": "arn:aws:events:us-east-1:000000000000:replay/ReplayTest",
    "State": "COMPLETED",
    "EventSourceArn": "arn:aws:events:us-east-1:000000000000:archive/ArchiveTest",
    "Destination": {
        "Arn": "arn:aws:events:us-east-1:000000000000:event-bus/test-event-bus"
    },
    ...
}

Replayed events will contain metadata to distinguish them from original events. You can check LocalStack logs for Lambda invocation details:

2024-08-06T07:29:24.039  INFO --- [et.reactor-1] localstack.request.aws     : AWS events.StartReplay => 200
2024-08-06T07:29:24.681  INFO --- [et.reactor-0] localstack.request.http    : POST /_localstack_lambda/58324d0bbf2060f95e80830df11f08a8/status/58324d0bbf2060f95e80830df11f08a8/ready => 202
2024-08-06T07:29:24.720  INFO --- [et.reactor-1] localstack.request.http    : POST /_localstack_lambda/58324d0bbf2060f95e80830df11f08a8/invocations/091a672b-a832-4824-a4cc-d56c75ed9893/logs => 202
2024-08-06T07:29:24.721  INFO --- [et.reactor-0] localstack.request.http    : POST /_localstack_lambda/58324d0bbf2060f95e80830df11f08a8/invocations/091a672b-a832-4824-a4cc-d56c75ed9893/response => 202

On the CloudWatch Logs Resource Browser, you can inspect the /aws/lambda/LogScheduledEvent log to view the received event:

Conclusion

With EventBridge Archive & Replay, you can capture and replay past events to troubleshoot issues or reprocess events through newly added functionalities without manually storing your events or setting up an additional infrastructure layer like Dead Letter Queues (DLQ), which can be time-consuming depending on the event consumer. LocalStack lets you test these event-driven workflows locally, simplifying the development loop and reducing development costs.

LocalStack’s EventBridge emulation supports testing event transmission across different AWS regions and accounts, integration with various targets (such as SNS, SQS, Step Functions), and Cloud Pods for state sharing & collaboration. In upcoming blog posts, we will delve into some of these use cases, showcasing how LocalStack can make the black box of event-driven systems transparent for developers.

10
Subscribe to my newsletter

Read articles from Harsh Bardhan Mishra directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Harsh Bardhan Mishra
Harsh Bardhan Mishra

Hi 👋 My name is Harsh and I'm an Engineer at LocalStack. I write about Open-Source projects, Cloud Toolings, DevOps, and automation!