Search code examples
c#azuresignalrazureservicebussignalr-hub

Getting userName in ProcessErrorAsync handler in azure service bus


I have the following system components:

  • Azure service bus
  • IHostedService as background "thread" that listen azure service bus
  • SignalR host that sends message to a client when ProcessMessageAsync completed.

SignalR is configured to use groups with the name taken from UserName.

public class NotificationHub : Hub
{
    public override async Task OnConnectedAsync()
    {
        var userName = Context!.User!.Identity!.Name ?? "Empty";
        var userGroupName = CreateUserGroupName(userName);
        await Groups.AddToGroupAsync(Context.ConnectionId, userGroupName);
        await base.OnConnectedAsync();
    }

    private static string CreateUserGroupName(string userName) => $"user_{userName}";
}

Sending message (from ihostedservice) happens in this way:

    var userGroupName = CreateUserGroupName(userName ?? "Empty");
    var group = _notificationHub.Clients.Group(userGroupName);
    await group.SendAsync(
        method: "OnReceived",
        arg1: arg1);

when I call the above from ProcessMessageAsync, all is good. I have userName (to get group name) in the body of income message.

Now I want to send a signalR message to the customer UI in case of azure service bus error (from ProcessErrorAsync callback), but ProcessErrorAsync doesn't have access to the income message and therefore to the userName. How can I get userName in ProcessErrorAsync? How such case usually handled?


Solution

  • ProcessErrorAsync() documentation states

    The handler responsible for processing unhandled exceptions thrown while this processor is running. Implementation is mandatory.

    There are a few scenarios this handler would be invoked. Most common would be:

    1. Intermittent message processing error. Usually resolved automatically by retrying the message when it's redelivered by Azure Service Bus. Assuming MaxDeliveryCount is not set mistakenly to one.
    2. Failure to process message due to logical bug in the processing handler +user code).
    3. Invalid payload that fails internal AMPQ conversion to .NET type.

    The failing message, valid or not, eventually will make it to the dead-letter queue. Dead-letter queue can be processed with its own processor instance and emit SignalR messages, assuming message can be read.

    TLDR: ProcessErrorAsync() is not intended for message processing but rather for logging and metrics. Use dead-letter queue if a custom logic for messages failing all retries is needed.