Skip to content

EventHub component delivers out of order messages (pubsub, binding) #3568

@oising

Description

@oising

Expected Behavior

When using Event Hubs as a pubsub or binding, messages should be delivered in the order they were posted (assume PartitionKey is set when publishing/posting to ensure ordering across partitions.)

Actual Behavior

In the pubsub case, the sidecar delivers new events before the subscriber has completed handling the last one. This causes major problems when trying to ensure order sensitive work is executed correctly (e.g. starting a workflow to process subsequent events.)

Steps to Reproduce the Problem

We're publishing to our topic like this (dotnet sdk):

await dapr.PublishEventAsync(
        WellKnownPubSubNames.Percept,
        WellKnownPubSubTopics.RecordingSessionFileEventV1, 
        data,
        new Dictionary<string, string>
        {
            { "partitionKey", data.DeviceId }
        }
    );

and receiving like this:

pubsub.MapPost(
    WellKnownPubSubTopics.RecordingSessionFileEventV1,
    [Topic(WellKnownPubSubNames.Percept, WellKnownPubSubTopics.RecordingSessionFileEventV1)]
    async (
        [FromServices] ILogger<Program> logger,
        [FromServices] IRecordingSessionRepository recordingSessionRepository,
        HttpContext HttpContext,
        [FromBody] RecordingSessionFileEventV1 data
    ) => {
        try {
            var messageId = HttpContext.Request.Headers["Message-Id"];

            logger.LogInformation("Start message id: {messageId}", messageId!);

            await Task.Delay(500);

            logger.LogInformation("Stop message id: {messageId}", messageId!);

            return Results.Ok();
        }
        catch (Exception ex) {
            logger.LogError(ex);
            return Results.Problem(ex.Message);
        }
    }
);

The problem is clear when watching the logs: instead of seeing a constant start/stop/start/stop alternating sequence of log events, we're seeing start/stop/start/start/stop/stop interleaving. The sidecar should not be sending another event until the current one has completed processing, i.e. it receives a http 200 (in this case.)

The same issue likely occurs for the binding since the common code is the problem (according to @yaron2):

It appears our implementation is using goroutines for each message, which would cause out-of-order delivery: https://github.com/dapr/components-contrib/blob/main/common/component/azure/eventhubs/eventhubs.go#L293. We do have a concurrency mechanism for components, it just hasn't been applied to Event Hubs. This should be an easy change - can you please open an issue in components-contrib for this? I'll add it to the v1.15 milestone

Release Note

PubSub and Binding components using ordered delivery (with a partitionkey) would interleave event deliveries to a subscriber. Now the sidecar will wait until the handler returns before sending the next event.

RELEASE NOTE:

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions