C# Azure服务总线未检测到重复项
我有一个进程,从Azure服务总线队列读取消息,并将该消息转换为要由Azure媒体服务编码的视频。我注意到,如果这个过程连续快速启动,同一个视频就会一个接一个地被编码。下面是我将视频添加到队列的代码C# Azure服务总线未检测到重复项,c#,azure,azureservicebus,C#,Azure,Azureservicebus,我有一个进程,从Azure服务总线队列读取消息,并将该消息转换为要由Azure媒体服务编码的视频。我注意到,如果这个过程连续快速启动,同一个视频就会一个接一个地被编码。下面是我将视频添加到队列的代码 public class VideoManager { string _connectionString = ConfigurationManager.AppSettings["Microsoft.ServiceBus.ConnectionString"]; string _queu
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部分中所述):
问题不在于完成(就像代码中那样),而在于实际上您有多个使用者(25个并发回调),而且锁定持续时间的流逝似乎比处理速度快。因此,消息会重新出现并重新处理。因此,您会多次看到相同的消息ID被记录 可能的解决方案有(如我在上文a部分中所述):