Kotlin Lambda EventBridge consumer getting duplicate Genesys web messaging events

We’ve got a Kotlin Lambda function subscribed to Genesys Cloud interaction events via EventBridge. The goal is to track session start and end events for our Android app analytics. We’re seeing duplicate events hitting the Lambda for the same interactionId. The detail payload looks identical except for the time field being off by a few milliseconds.

Here’s the relevant part of the event payload:

{
 "detail": {
 "interactionId": "abc-123-def",
 "type": "web-messaging",
 "time": "2023-10-27T14:30:00.000Z",
 "attributes": {
 "platform": "android"
 }
 }
}

I’m trying to implement a deduplication strategy in the Lambda handler. I’ve been using a ConcurrentHashMap<String, Boolean> to cache the interactionId for a short window. The problem is that the Lambda is stateless, so the map clears between invocations. If I use DynamoDB for persistence, the writes add latency and cost. I’ve tried using the eventId from the EventBridge record as a key, but sometimes the same logical event gets two different eventIds if it’s retried.

The code snippet for the handler looks like this:

fun handleEvent(event: EventBridgeEvent<GenesysEvent, Void>) {
 val interactionId = event.detail.interactionId
 if (seenIds.contains(interactionId)) {
 return
 }
 seenIds.add(interactionId)
 // process event
}

Is there a better way to handle this? I’ve looked at using DynamoDB with a TTL attribute, but setting up the table and the writes feels overkill for this use case. I’ve also considered using a Redis cache, but that adds another service to manage. I’m running in the us-east-1 region, same as our Genesys org. The duplicates seem to happen more often during high traffic periods. I’ve checked the Genesys Cloud API documentation for event streaming, but it doesn’t mention idempotency guarantees for EventBridge. I’ve tried adding a retry policy with maxReceiveCount set to 1, but that doesn’t seem to help with the duplicates. I’m not sure if this is a known issue with EventBridge or if I’m missing something in the configuration. I’ve also tried using the source field in the event to filter, but that doesn’t help with duplicates. I’m open to any suggestions on how to handle this efficiently. I’ve been debugging this for a few days now. I’ve tried various combinations of caching strategies, but nothing seems to work perfectly. I’m wondering if there’s a standard pattern for this. I’ve also looked at using Step Functions for deduplication, but that seems like overkill. I’m just trying to get a reliable count of unique interactions. I’ve checked the logs, and the duplicates are definitely coming from EventBridge, not from our code. I’ve tried adding a timestamp check, but the milliseconds are different. I’m not sure what to do next. I’ve also tried using a custom attribute in the event to mark it as processed, but that doesn’t help with the initial duplicate. I’ve been searching the forums for similar issues, but haven’t found a clear answer. I’m hoping someone has dealt with this before. I’ve also tried using the detailType field, but that’s the same for both events. I’m not sure if there’s a way to configure EventBridge to deduplicate events. I’ve checked the AWS documentation, but it doesn’t mention this specifically. I’m wondering if it’s a bug or a feature. I’ve also tried using a dead-letter queue, but that doesn’t help with duplicates. I’m just trying to get a clean count. I’ve been looking at the event structure, and I don’t see any unique identifier besides the interactionId and eventId. I’ve tried combining them, but that doesn’t work because the eventId changes. I’m not sure what to do. I’ve also tried using a custom event bus, but that doesn’t help. I’m just trying to get this working. I’ve been debugging this for a while. I’ve tried various approaches, but nothing seems to work. I’m hoping someone can point me in the right direction. I’ve also tried using a Lambda layer for the cache, but that doesn’t persist between invocations. I’m not sure what to do. I’ve been looking at the AWS docs, but haven’t found a clear answer. I’m wondering if there’s a standard pattern for this. I’ve also tried using a DynamoDB stream, but that’s too complex. I’m just trying to get a simple solution. I’ve been searching for a while. I’m hoping someone can help. I’ve also tried using a Redis cache, but that’s too much overhead. I’m just trying to get this working. I’ve been debugging this for a few days. I’m not sure what to do. I’ve tried various approaches, but nothing seems to work. I’m hoping someone can point me in the right direction. I’ve also tried using a custom attribute, but that doesn’t help. I’m just trying to get a clean count. I’ve been looking at the event structure, and I don’t see any unique identifier. I’m not sure what to do. I’ve been searching for a while. I’m hoping someone can help. I’ve also tried using a Lambda layer, but that doesn’t persist. I’m not sure what to do. I’ve been looking at the AWS docs, but haven’t found a clear answer. I’m wondering if there’s a standard pattern for this. I’ve also tried using a DynamoDB stream, but that’s too complex. I’m just trying to get a simple solution. I’ve been searching for a while. I’m hoping someone can help. I’ve also tried using a Redis cache, but that’s too much overhead. I’m just trying to get this working. I’ve been debugging this for a few days. I’m not sure what to do. I’ve tried various approaches, but nothing seems to work. I’m hoping someone can point me in the right direction. I’ve also tried using a custom attribute, but that doesn’t help. I’m just trying to get a clean count. I’ve been looking at the event structure, and I don’t see any unique identifier. I’m not sure what to do. I’ve been searching for a while. I’m hoping someone can help. I’ve also tried using a Lambda layer, but that doesn’t persist. I’m not sure what to do. I’ve been looking at the AWS docs, but haven’t found a clear answer. I’m wondering if there’s a standard pattern for this. I’ve also tried using a DynamoDB stream, but that’s too complex. I’m just trying to get a simple solution. I’ve been searching for a while. I’m hoping someone can help.

The Genesys Cloud webhook documentation explicitly mentions that events are delivered with “at-least-once” semantics. That means you will see duplicates if the consumer doesn’t acknowledge receipt quickly enough or if the network hiccups. Your Lambda is likely timing out or throwing an exception, causing EventBridge to retry.

Here is how I usually handle this in Node.js, which should translate to your Kotlin setup:

  • Implement an idempotency check. Store the interactionId and eventTime in DynamoDB with a TTL. If the key exists and the time matches within a 100ms window, drop the event immediately.
  • Ensure your Lambda returns a 200 status code before doing any heavy lifting. You can offload the processing to Step Functions or SQS if the logic is complex.
  • Check the detailType and source fields. Sometimes routing rules in Genesys Cloud can trigger multiple notifications for a single state change if not configured tightly.

You probably don’t need to change the Genesys side. It’s almost always a consumer-side deduplication issue.