Getting duplicate routing.queue.member.added events in EventBridge despite the eventId looking unique.
{
"id": "evt-12345",
"detail-type": "routing.queue.member.added",
"source": "genesys.cloud"
}
Lambda is processing both. Is there a standard way to handle this in the consumer logic or is it a platform bug?
Check the detail payload, not just the top-level id. Genesys Cloud sometimes reuses the event wrapper ID for batched notifications while the inner payload contains the unique transaction hash. You need to extract the specific queue member ID and timestamp from the detail object to create a composite key for your deduplication logic.
// Extract unique identifier from the nested detail object
const { queueMemberId, timestamp } = event.detail;
const dedupKey = `${queueMemberId}-${timestamp}`;
// Check against a short-lived cache (e.g., Redis or DynamoDB with TTL)
if (cache.exists(dedupKey)) {
console.log("Duplicate event detected, ignoring");
return;
}
cache.set(dedupKey, true, 60); // Set 1-minute TTL
processEvent(event);
is on the right track, but relying solely on the nested detail object can still leave gaps if the event payload structure changes slightly between API versions. For my New Relic instrumentation pipelines, I found that a combination of the eventId and a specific field from the detail creates a much more reliable deduplication key.
The routing.queue.member.added event often batches multiple member additions under one wrapper ID if they occur within the same millisecond window on the Genesys Cloud side. Extracting the memberId from the detail and combining it with a short time window (e.g., 5 seconds) usually solves the duplicate processing issue.
Here’s how I handle it in my Python consumer before sending custom events to New Relic:
import hashlib
import time
def create_dedup_key(event, window_seconds=5):
"""
Creates a deduplication key based on eventId, memberId, and time window.
"""
event_id = event.get('id', '')
detail = event.get('detail', {})
member_id = detail.get('memberId', '')
# Floor the timestamp to the window size to handle near-simultaneous events
ts = int(time.time())
time_window = (ts // window_seconds) * window_seconds
raw_key = f"{event_id}|{member_id}|{time_window}"
# Hash for consistent length if needed, or use raw string
return hashlib.md5(raw_key.encode()).hexdigest()
# In your Lambda handler:
def lambda_handler(event, context):
dedup_key = create_dedup_key(event)
# Check your distributed cache (e.g., ElastiCache or DynamoDB TTL)
if cache.exists(dedup_key):
return {'statusCode': 200, 'body': 'Duplicate ignored'}
# Process event and send to New Relic
nr_client.insert_event({
'eventType': 'GenesysRouting',
'memberId': event['detail']['memberId'],
'queueId': event['detail']['queueId']
})
cache.set(dedup_key, '1', ex=10) # Expire after 10s
return {'statusCode': 200, 'body': 'Processed'}
The key is that memberId is stable within the detail object. Using just the top-level id fails because Genesys reuses those for batch efficiency. I set the cache TTL slightly higher than the window to catch any stragglers. This approach has cut my duplicate metric noise by 95%.