Event-Driven Application using AWS EventBridge and Lambda in Java — Part 1

Raghunandan Gupta
6 min readApr 29, 2021

Now days building Event-Driven Applications is a necessity. In the early days, it was not required nor anyone gave more importance to it because in some way or other existing Applications were fulfilling Customer needs.

Soon when scale started to increase having one monolith application doing everything was not enough. With more scale comes more responsibility because now if you fail it’s big. We have seen companies deploying more resources either in terms of infra or manpower at the time of year-end or Christmas sale etc.

Microservices have been used for quite some time. People who have used Micro Services are always in a dilemma about how to communicate with other services. Sending data using APIs (HTTPS) directly to the service was is one such way. In case of failure, Retry Mechamins are always handy. APIs have their own limitations because now you are dependent on other Systems whose availability depends on the working and priority of the dependent service.

I will try to explain using Architecture Diagrams.

The above pattern is quite common in most applications. It is mainly used to

  • Display Aggregate results using APIs
  • Sending request to multiple Services

The above pattern is also common in most Applications also known as Event-Driven Design.

  • Sending event to Distributed Event Management System
  • Multiple Services Subscribes to Event System and receive the data

Open Source Solutions

  • Apache Kafka
  • Rabbit MQ
  • etc.

Cloud Offerings

  • Amazon SQS
  • Event Buses
  • Kafka
  • etc.

Let’s understand a use case.

You are in a Digital Marketing Company and you are working on a MultiTenant Application where multiple Customer can create Campaigns and send out mail according to the User Profiles Created by Customers. There is a dashboard where Customer can see the stats but Customer wants to create their own dashbaord or want to share the data with others to provide insights. To summarize they want few specific events from your Application.

In the above use case, there can be multiple solutions

  • Use of Houry/Daily Data dump and make available to the Client using either FTP or S3 or HDFS etc.
  • Create one more Custom Connector with some rules and send data to the Customer’s API (WebHook)

Custom Connector will have some rules, validations, etc in place to filter out only events that need to send to the end Customer. If you have similar use case architecture will be the same as above plus few more components like Enricher, Filter, Rule Manager, Databases, Load Balancers, Cache, etc.

Using AWS Event Bridge to solve Similar use case

Event Bridge is more advance compared to the Event bus provided by AWS but underneath it uses Event bus only but with more Features. It is easy to send and consume events from Event Bridge. Event Bridge comes with Default Event Bus as well but we can create our own Custom Event Bus on the basis of requirement. We can publish events on this Custom Event Bus.

Event Bridge Event Buses

During my exploration, I found an outstanding feature in the Event Bridge. We can create rules in Event Bridge on any Event Bus. Rules are basically pattern which will be matched with Events that are sent to Event Bus. We can add Target means destination in Event Bridge where the matched event will be sent. e.g. Lambda, APIs, Kinesis, SQS, and SNS, etc.

Event Bridge Rules

Custom Pattern

{
"source": ["app.tracking.events"],
"detail-type": ["Click Event"],
"detail": {
"city": ["NJ"]
}
}

Source and Details Type are used to identify the events. In our case, we have named it as per the Java Package Standard or any other. Details Type tells about the details of the Event and in Details, we can have our original Payload.

Sample Event Payload

{
"source": "app.tracking.events",
"detail-type": "Click Event",
"detail": {
"name": "John",
"age": 31,
"city": "NJ"
}
}

When we send the above Event Payload it will match and send an event to configured Target. We can configure many rules and provide different Targets.

Click to View More Event Bridge Patterns

Consumed Event Payload in Target

{
"detail": {
"name": "John",
"age": 31,
"city": "NJ"
},
"resources": [],
"id": "9fd5857c-f704-9a70-4d1e-2ed2ada184ba",
"source": "app.tracking.events",
"time": "Apr 28, 2021, 7:03:50 PM",
"region": "us-east-1",
"version": "0",
"account": "xxxxxxxxxxx"
}

More about Event Bridge Quotas

AWS Lambda — Event Producer

I write a simple Lambda Function to Test the above scenario and integrated it with the Event Bus. You have to make sure that your Lamda Function has a role that should have enough Permission to Execute the Lambda Function and Send the Event to Event Bridge. I gave full access for testing purposes but it would be good to provide granular permission to make sure if Somebody changes the Lambda Function code, in that case, the Lambda function should not be able to do something else other than its regular job.

public class Producer implements RequestHandler<Map<String, String>, String> {

LambdaLogger logger = null;
Gson gson = new GsonBuilder().setPrettyPrinting().create();

public String handleRequest(final Map<String, String> input, final Context context) {
logger = context.getLogger();
if (Objects.nonNull(input)) {
String data = gson.toJson(input);
logger.log("Data :: " + data);

AmazonEventBridge amazonEventBridge = AmazonEventBridgeClient.builder()
.withRegion(Regions.US_EAST_1)
.build();
putEventsToBridge(amazonEventBridge, data);
return "200 OK";
} else {
logger.log("Data is null.");
return "400 BAD Request";
}
}

public void putEventsToBridge(AmazonEventBridge amazonEventBridge, String event) {
PutEventsRequestEntry putEventsRequestEntry = new PutEventsRequestEntry();
putEventsRequestEntry = putEventsRequestEntry.withSource("app.tracking.events")
.withEventBusName("test-eventbus")
.withTime(Calendar.getInstance().getTime())
.withDetailType("Click Event")
.withDetail(event);

PutEventsRequest putEventsRequest = new PutEventsRequest();
putEventsRequest.withEntries(putEventsRequestEntry);
PutEventsResult putEventsResult = amazonEventBridge.putEvents(putEventsRequest);

logger.log("Event Bridge Response = " + putEventsResult.getFailedEntryCount());
}
}

Event Class

public class CustomEvent implements Serializable {

private String name;
private Integer age;
private String city;

public CustomEvent() {
}

public CustomEvent(String name, Integer age, String city) {
this.name = name;
this.age = age;
this.city = city;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public String getCity() {
return city;
}

public void setCity(String city) {
this.city = city;
}
}

AWS Lambda Consumer

We consume the event from the Event Bus and Printing it.

public class Consumer implements RequestHandler<EventBridgeConsumerEvent<CustomEvent>, String> {

LambdaLogger logger = null;
Gson gson = new GsonBuilder().setPrettyPrinting().create();

@Override
public String handleRequest(EventBridgeConsumerEvent<CustomEvent> input, Context context) {
logger = context.getLogger();
if(Objects.nonNull(input)) {
String data = gson.toJson(input);
logger.log("Data :: "+ data);
} else {
logger.log("Data is null.");
}
return "Accepted";
}
}

Testing

  • Send event using Producer Lambda Function
  • Go to Consumer Lambda Function -> Monitoring -> Cloud Watch Logs
  • Click on Cloud Watch Logs

Next, I will explore Schema Registry in Event Bridge.

Additional Links

~ Thanks.

--

--

Raghunandan Gupta

I am a coder by heart and try to learn new things along with sharpening existing skills. https://www.linkedin.com/in/raghunitb/