Unique IDs for multiple events raised by one command & idempotency

I have a service that handles a command CmdA { id = “100” , …}. This turns into a command invoked on an aggregate that produces two events EvA and EvB - not a frequent use case, but still can happen.

To ensure idempotency, I generate a deterministic id based on command’s id (“100”), for ex “abcd” and use it as EventId for those two events.

Now I have two events tagged with the same id. However, these events (being enriched and transformed into integration events) need to be reported to downstream systems and need unique id for each events.

I am inclined to generate unique ids for events and store them as part of event body. In this case, the EventStore’s event id is turned into a “commit id” that will be used for idempotence purposes only.

Is there a better way to tackle the above task?

Use a unique ID for each event but introduce a correlation ID that you share among all related events. If you at least use EventStoreDB Version 5, you could also use the by-correlation-id system projection to easily access them after the fact.

If you go that route, keep in mind projections can have an impact on the server performance: https://developers.eventstore.com/server/v20/server/projections/#performance-impact

Do you mean keeping unique id as part of event body?

I would advise to, even if you used that id as an event-id in EventStoreDB

EventStore already has idempotency functionality built in. You can set EventData.EventId with a deterministic Uuid (or Guid in the TCP client) with the command id and the nth position of the event.