C# Azure服务总线未检测到重复项

C# Azure服务总线未检测到重复项,c#,azure,azureservicebus,C#,Azure,Azureservicebus,我有一个进程,从Azure服务总线队列读取消息,并将该消息转换为要由Azure媒体服务编码的视频。我注意到,如果这个过程连续快速启动,同一个视频就会一个接一个地被编码。下面是我将视频添加到队列的代码 public class VideoManager { string _connectionString = ConfigurationManager.AppSettings["Microsoft.ServiceBus.ConnectionString"]; string _queu

我有一个进程,从Azure服务总线队列读取消息,并将该消息转换为要由Azure媒体服务编码的视频。我注意到,如果这个过程连续快速启动,同一个视频就会一个接一个地被编码。下面是我将视频添加到队列的代码

public class VideoManager
{
    string _connectionString = ConfigurationManager.AppSettings["Microsoft.ServiceBus.ConnectionString"];
    string _queueName = ConfigurationManager.AppSettings["ServiceBusQueueName"];
    QueueClient _client;

    public VideoManager()
    {
        var conStringBuilder = new ServiceBusConnectionStringBuilder(_connectionString)
        {
            OperationTimeout = TimeSpan.FromMinutes(120)
        };

        var messagingFactory = MessagingFactory.CreateFromConnectionString(conStringBuilder.ToString());
        _client = messagingFactory.CreateQueueClient(_queueName);
    }

    public void Approve(Video video)
    {
        // Set video to approved. 
        video.ApprovalStatus = ApprovalStatus.Approved;
        var message = new BrokeredMessage(new VideoMessage(video, VideoMessage.MessageTypes.Approve, string.Empty));
        message.MessageId = video.RowKey;
        _client.Send(message);
    }
}
 class Program
{
    static QueueClient client;

    static void Main(string[] args)
    {
        VideoManager videoManager = new VideoManager();

        var connectionString = ConfigurationManager.AppSettings["Microsoft.ServiceBus.ConnectionString"];

        var conStringBuilder = new ServiceBusConnectionStringBuilder(connectionString)
        {
            OperationTimeout = TimeSpan.FromMinutes(120)
        };

        var messagingFactory = MessagingFactory.CreateFromConnectionString(conStringBuilder.ToString());

        client = messagingFactory.CreateQueueClient(ConfigurationManager.AppSettings["ServiceBusQueueName"]);

        Console.WriteLine("Starting: Broadcast Center Continuous Video Processing Job");

        OnMessageOptions options = new OnMessageOptions
        {
            MaxConcurrentCalls = 25,
            AutoComplete = false
        };

        client.OnMessageAsync(async message =>
        {
            bool shouldAbandon = false;

            try
            {
                await HandleMessage(message);
            }
            catch (Exception ex)
            {
                shouldAbandon = true;
                Console.WriteLine(ex.Message);
            }
            if (shouldAbandon)
            {
                await message.AbandonAsync();
            }
        }, options);
        while (true) { }
    }
    async static Task<int> HandleMessage(BrokeredMessage message)
    {

        VideoMessage videoMessage = message.GetBody<VideoMessage>();

        Console.WriteLine(String.Format("Message body: {0}", videoMessage.Video.Title));
        Console.WriteLine(String.Format("Message id: {0}", message.MessageId));

        VideoProcessingService vp = new VideoProcessingService(videoMessage.Video);
        Task task;
        switch (videoMessage.MessageType)
        {
            case VideoMessage.MessageTypes.CreateThumbnail:
                task = new Task(() => vp.ProcessThumbnail(videoMessage.TimeStamp));
                task.Start();

                while (!task.IsCompleted)
                {
                    await Task.Delay(15000);
                    message.RenewLock();
                }
                await task;
                Console.WriteLine(task.Status.ToString());

                Console.WriteLine("Processing Complete");
                Console.WriteLine("Awaiting Message");
                break;
            case VideoMessage.MessageTypes.Approve:

                task = new Task(() => vp.Approve());
                task.Start();

                while (!task.IsCompleted)
                {
                    await Task.Delay(15000);
                    message.RenewLock();
                }
                await task;
                Console.WriteLine(task.Status.ToString());

                Console.WriteLine("Processing Complete");
                Console.WriteLine("Awaiting Message");
                break;
            default:
                break;
        }
        return 0;
    }
}
以及从队列中读取的进程

public class VideoManager
{
    string _connectionString = ConfigurationManager.AppSettings["Microsoft.ServiceBus.ConnectionString"];
    string _queueName = ConfigurationManager.AppSettings["ServiceBusQueueName"];
    QueueClient _client;

    public VideoManager()
    {
        var conStringBuilder = new ServiceBusConnectionStringBuilder(_connectionString)
        {
            OperationTimeout = TimeSpan.FromMinutes(120)
        };

        var messagingFactory = MessagingFactory.CreateFromConnectionString(conStringBuilder.ToString());
        _client = messagingFactory.CreateQueueClient(_queueName);
    }

    public void Approve(Video video)
    {
        // Set video to approved. 
        video.ApprovalStatus = ApprovalStatus.Approved;
        var message = new BrokeredMessage(new VideoMessage(video, VideoMessage.MessageTypes.Approve, string.Empty));
        message.MessageId = video.RowKey;
        _client.Send(message);
    }
}
 class Program
{
    static QueueClient client;

    static void Main(string[] args)
    {
        VideoManager videoManager = new VideoManager();

        var connectionString = ConfigurationManager.AppSettings["Microsoft.ServiceBus.ConnectionString"];

        var conStringBuilder = new ServiceBusConnectionStringBuilder(connectionString)
        {
            OperationTimeout = TimeSpan.FromMinutes(120)
        };

        var messagingFactory = MessagingFactory.CreateFromConnectionString(conStringBuilder.ToString());

        client = messagingFactory.CreateQueueClient(ConfigurationManager.AppSettings["ServiceBusQueueName"]);

        Console.WriteLine("Starting: Broadcast Center Continuous Video Processing Job");

        OnMessageOptions options = new OnMessageOptions
        {
            MaxConcurrentCalls = 25,
            AutoComplete = false
        };

        client.OnMessageAsync(async message =>
        {
            bool shouldAbandon = false;

            try
            {
                await HandleMessage(message);
            }
            catch (Exception ex)
            {
                shouldAbandon = true;
                Console.WriteLine(ex.Message);
            }
            if (shouldAbandon)
            {
                await message.AbandonAsync();
            }
        }, options);
        while (true) { }
    }
    async static Task<int> HandleMessage(BrokeredMessage message)
    {

        VideoMessage videoMessage = message.GetBody<VideoMessage>();

        Console.WriteLine(String.Format("Message body: {0}", videoMessage.Video.Title));
        Console.WriteLine(String.Format("Message id: {0}", message.MessageId));

        VideoProcessingService vp = new VideoProcessingService(videoMessage.Video);
        Task task;
        switch (videoMessage.MessageType)
        {
            case VideoMessage.MessageTypes.CreateThumbnail:
                task = new Task(() => vp.ProcessThumbnail(videoMessage.TimeStamp));
                task.Start();

                while (!task.IsCompleted)
                {
                    await Task.Delay(15000);
                    message.RenewLock();
                }
                await task;
                Console.WriteLine(task.Status.ToString());

                Console.WriteLine("Processing Complete");
                Console.WriteLine("Awaiting Message");
                break;
            case VideoMessage.MessageTypes.Approve:

                task = new Task(() => vp.Approve());
                task.Start();

                while (!task.IsCompleted)
                {
                    await Task.Delay(15000);
                    message.RenewLock();
                }
                await task;
                Console.WriteLine(task.Status.ToString());

                Console.WriteLine("Processing Complete");
                Console.WriteLine("Awaiting Message");
                break;
            default:
                break;
        }
        return 0;
    }
}
类程序
{
静态排队客户端;
静态void Main(字符串[]参数)
{
VideoManager VideoManager=新的VideoManager();
var connectionString=ConfigurationManager.AppSettings[“Microsoft.ServiceBus.connectionString”];
var conStringBuilder=new ServiceBusConnectionStringBuilder(connectionString)
{
OperationTimeout=TimeSpan.FromMinutes(120)
};
var messagingFactory=messagingFactory.CreateFromConnectionString(conStringBuilder.ToString());
client=messagingFactory.CreateQueueClient(ConfigurationManager.AppSettings[“ServiceBusQueueName]”);
Console.WriteLine(“启动:广播中心连续视频处理作业”);
OnMessageOptions=新的OnMessageOptions
{
MaxConcurrentCalls=25,
自动完成=错误
};
client.OnMessageAsync(异步消息=>
{
bool shouldDiscard=false;
尝试
{
等待HandleMessage(消息);
}
捕获(例外情况除外)
{
应该放弃=正确;
控制台写入线(例如消息);
}
如果(应该放弃)
{
等待消息。放弃异步();
}
},选项);
while(true){}
}
异步静态任务HandleMessage(BrokeredMessage消息)
{
VideoMessage VideoMessage=message.GetBody();
WriteLine(String.Format(“消息体:{0}”,videoMessage.Video.Title));
WriteLine(String.Format(“MessageId:{0}”,Message.MessageId));
VideoProcessingService vp=新的VideoProcessingService(videoMessage.Video);
任务;
开关(videoMessage.MessageType)
{
case VideoMessage.MessageTypes.create缩略图:
任务=新任务(()=>vp.process缩略图(videoMessage.TimeStamp));
task.Start();
而(!task.IsCompleted)
{
等待任务。延迟(15000);
message.RenewLock();
}
等待任务;
Console.WriteLine(task.Status.ToString());
Console.WriteLine(“处理完成”);
Console.WriteLine(“等待消息”);
打破
案例VideoMessage.MessageTypes.Approve:
任务=新任务(()=>vp.Approve());
task.Start();
而(!task.IsCompleted)
{
等待任务。延迟(15000);
message.RenewLock();
}
等待任务;
Console.WriteLine(task.Status.ToString());
Console.WriteLine(“处理完成”);
Console.WriteLine(“等待消息”);
打破
违约:
打破
}
返回0;
}
}
如果我连续启动流程3次,我在控制台窗口中看到的是以下内容

消息id:76aca19a-0698-449b-bf58-a24876fc4314

消息id:76aca19a-0698-449b-bf58-a24876fc4314

消息id:76aca19a-0698-449b-bf58-a24876fc4314

我想也许我没有正确的设置,但它们确实存在
我在这里真的很茫然,因为我希望这是一个相当开箱的行为。重复检测是否仅在消息已完成时有效,因此我无法使用OnMessageAsync()?

您的HandleMessage代码中缺少一行代码

async static Task<int> HandleMessage(BrokeredMessage message)
{
  VideoMessage videoMessage = message.GetBody<VideoMessage>();

  message.CompleteAsync(); // This line...

  Console.WriteLine(String.Format("Message id: {0}", message.MessageId));
  // Processes Message
}
异步静态任务句柄消息(BrokeredMessage消息)
{
VideoMessage VideoMessage=message.GetBody();
message.CompleteAsync();//此行。。。
WriteLine(String.Format(“MessageId:{0}”,Message.MessageId));
//处理消息
}
因此,是的,您必须使用、完成、延迟等标记消息


另请参见此,也可以发现这可能对重复检测的工作方式很有用

您的HandleMessage代码中缺少一行代码

async static Task<int> HandleMessage(BrokeredMessage message)
{
  VideoMessage videoMessage = message.GetBody<VideoMessage>();

  message.CompleteAsync(); // This line...

  Console.WriteLine(String.Format("Message id: {0}", message.MessageId));
  // Processes Message
}
异步静态任务句柄消息(BrokeredMessage消息)
{
VideoMessage VideoMessage=message.GetBody();
message.CompleteAsync();//此行。。。
WriteLine(String.Format(“MessageId:{0}”,Message.MessageId));
//处理消息
}
因此,是的,您必须使用、完成、延迟等标记消息


还可以看到这一点,也可以发现这一点可能对重复检测的工作方式很有用。问题不在于完成(正如代码中所述),而在于实际上您有多个使用者(25个并发回调),而且锁定持续时间的流逝似乎快于处理所需的时间。因此,消息会重新出现并重新处理。因此,您会多次看到相同的消息ID被记录

可能的解决方案有(如我在上文a部分中所述):

  • 让OnMessageAPI为您管理超时扩展()
  • 手动更换锁,就像您使用

  • 问题不在于完成(就像代码中那样),而在于实际上您有多个使用者(25个并发回调),而且锁定持续时间的流逝似乎比处理速度快。因此,消息会重新出现并重新处理。因此,您会多次看到相同的消息ID被记录

    可能的解决方案有(如我在上文a部分中所述):

  • 让OnMessageAPI为您管理超时扩展()
  • 按照您的要求手动更换锁