Azure webjob 似乎不遵守 MaxDequeueCount 属性
Azure webjob not appearing to respect MaxDequeueCount property
我有一个带有几个 queue-triggered 函数的 Azure webjob。 https://docs.microsoft.com/en-us/azure/app-service-web/websites-dotnet-webjobs-sdk-storage-queues-how-to#config 处的 SDK 文档将 MaxDequeueCount
属性 定义为:
The maximum number of retries before a queue message is sent to a
poison queue (default is 5).
但我没有看到这种行为。在我的网络作业中,我有:
JobHostConfiguration config = new JobHostConfiguration();
config.Queues.MaxDequeueCount = 1;
JobHost host = new JobHost(config);
host.RunAndBlock();
然后我有一个 queue-triggered 函数,我在其中抛出异常:
public void ProcessQueueMessage([QueueTrigger("azurewejobtestingqueue")] string item, TextWriter logger)
{
if ( item == "exception" )
{
throw new Exception();
}
}
查看 webjobs 仪表板,我看到 SDK 进行了 5 次尝试(如上所述默认为 5 次):
在第 5 次尝试后,邮件将移至毒物队列。我希望看到 1 次重试(或没有重试?)而不是 5 次。
更新:为 web 应用程序启用了详细的日志记录,并选择将这些日志保存到 Azure blob 容器中。在 azure-jobs-host-archive
容器中找到了一些与我的问题相关的日志。下面的示例显示出列计数为 96 的项目:
{
"Type": "FunctionCompleted",
"EndTime": "2017-02-22T00:07:40.8133081+00:00",
"Failure": {
"ExceptionType": "Microsoft.Azure.WebJobs.Host.FunctionInvocationException",
"ExceptionDetails": "Microsoft.Azure.WebJobs.Host.FunctionInvocationException: Exception while executing function: ItemProcessor.ProcessQueueMessage ---> MyApp.Exceptions.MySpecialAppExceptionType: Exception of type 'MyApp.Exceptions.MySpecialAppExceptionType' was thrown.
},
"ParameterLogs": {},
"FunctionInstanceId": "1ffac7b0-1290-4343-8ee1-2af0d39ae2c9",
"Function": {
"Id": "MyApp.Processors.ItemProcessor.ProcessQueueMessage",
"FullName": "MyApp.Processors.ItemProcessor.ProcessQueueMessage",
"ShortName": "ItemProcessor.ProcessQueueMessage",
"Parameters": [
{
"Type": "QueueTrigger",
"AccountName": "MyStorageAccount",
"QueueName": "stuff-processor",
"Name": "sourceFeedItemQueueItem"
},
{
"Type": "BindingData",
"Name": "dequeueCount"
},
{
"Type": "ParameterDescriptor",
"Name": "logger"
}
]
},
"Arguments": {
"sourceFeedItemQueueItem": "{\"SourceFeedUpdateID\":437530,\"PodcastFeedID\":\"2d48D2sf2\"}",
"dequeueCount": "96",
"logger": null
},
"Reason": "AutomaticTrigger",
"ReasonDetails": "New queue message detected on 'stuff-processor'.",
"StartTime": "2017-02-22T00:07:40.6017341+00:00",
"OutputBlob": {
"ContainerName": "azure-webjobs-hosts",
"BlobName": "output-logs/1ffd3c7b012c043438ed12af0d39ae2c9.txt"
},
"ParameterLogBlob": {
"ContainerName": "azure-webjobs-hosts",
"BlobName": "output-logs/1cf2c1b012sa0d3438ee12daf0d39ae2c9.params.txt"
},
"LogLevel": "Info",
"HostInstanceId": "d1825bdb-d92a-4657-81a4-36253e01ea5e",
"HostDisplayName": "ItemProcessor",
"SharedQueueName": "azure-webjobs-host-490daea03c70316f8aa2509438afe8ef",
"InstanceQueueName": "azure-webjobs-host-d18252sdbd92a4657d1a436253e01ea5e",
"Heartbeat": {
"SharedContainerName": "azure-webjobs-hosts",
"SharedDirectoryName": "heartbeats/490baea03cfdfd0416f8aa25aqr438afe8ef",
"InstanceBlobName": "zd1825bdbdsdgga465781a436q53e01ea5e",
"ExpirationInSeconds": 45
},
"WebJobRunIdentifier": {
"WebSiteName": "myappengine",
"JobType": "Continuous",
"JobName": "ItemProcessor",
"RunId": ""
}
}
不过,我进一步寻找的是日志,这些日志会向我显示处理成功(并因此从队列中删除)或因异常而失败并放入毒物队列的特定队列项目的详细信息.到目前为止,我还没有找到任何显示该细节的日志。上面输出中引用的日志文件不包含此类数据。
更新 2:查看了我的毒药队列的状态,它似乎是确凿的证据,但我太笨了,无法将 2 和 2 放在一起。查看下面队列的屏幕截图,您可以在其中多次看到带有 ID(左列)431210
的消息。它多次出现的事实告诉我,原始队列中的消息失败不正确。
我怀疑这是因为您实际上 运行 不是您认为自己在 Azure 中的二进制文件。这个也让我陷入了困境。
当您 运行 在 Azure 上触发 WebJobs 时,发布新版本的 WebJob 不会导致立即卸载旧的触发 WebJob 并启动新的 WebJob。如果您查看 WebJob 日志,我怀疑您在重新发布时不会看到重新启动。
这是因为默认情况下,Kudu 会将所有 WebJob 文件复制到临时目录并执行它们。来自 Kudu WebJob docs:
The WebJob is copied to a temporary directory under %TEMP%\jobs{job
type}{job name}{random name} and will run from there This option
prevents the original WebJob binaries from being locked which might
cause issues redeploying the WebJob. For example updating an .exe file
that is currently running.
我在确保新发布的触发 WebJob 实际上是 运行 方面取得的唯一成功是执行以下操作:
登录到 Kudu 控制台。是 https://yourappname.scm.azurewebsites.net。您将使用与登录 Azure 门户时相同的凭据。
登录后,单击顶部的 Process Explorer 菜单选项。找到当前 运行 的 WebJob 进程,然后将其终止。
FTP 到您的 Web 应用程序。浏览到包含您的 WebJob 代码的目录,然后将其删除。它应该在 /app_data/jobs/triggered/[您的网络作业名称].
下
然后我跳到门户,通过 Web 应用程序管理浏览到托管 WebJob 的 blade,单击 WebJobs 菜单选项,并确认旧的 WebJob 不再存在那里。
从 Visual Studio 发布我的新 WebJob。
这应该可以保证您是 运行 您发布的代码。希望这可以帮助。
MaxDequeueCount 属性 如果我配置它,它对我来说工作正常。
所以很奇怪它对你不起作用。当我设置
config.Queues.MaxDequeueCount = 2;
然后我得到了预期的结果请参考截图。
我们也可以使用dequeueCount
来控制重试次数。以下是不尝试的demo代码
public void ProcessQueueMessage([QueueTrigger("queue")] string item, int dequeueCount, TextWriter logger)
{
if (dequeueCount == 1)
{
if (item == "exception")
{
throw new Exception();
}
logger.WriteLine($"NewMsge: {item}");
Console.WriteLine($"NewMsge: {item}");
}
}
日志信息请参考截图
我看到同样的事情,消息超过了最大出队计数。稍后我会 post 更多详细信息,但我也看到似乎有非常大的数字最终进入了毒药队列。所以我怀疑它在 5 之后添加到毒物队列中,但是尝试更多最终导致毒物队列中有很多(数百个)。
如果您仍在寻找答案,我们尝试了列出的一些答案但没有成功。事实证明这是 Storage sdk (WindowsAzure.Storage) 和 Webjob sdk (Microsoft.Azure.WebJobs) 的版本问题。为了修复它,我们最终不得不将我们的存储 sdk 版本降级到 7.2.1(我们最近升级到 8.1.1)。根据下面的文章,工程师们现在已经意识到了这些问题,并希望尽快修复它:
如 Rob W 所述,使用 WindowsAzure.Storage > 7.1.2 时存在此问题。该问题显然已在 issue #1141 中修复,但尚未发布。
贡献者asifferman has shared a code snippet in a comment post on issue #985。这似乎可以解决问题(对我来说效果很好)。
在 link rot 的情况下,为了满足 SO 规则,这里是 post 以及代码片段:
For those (like me) who cannot wait the next release to get the
WebJobs SDK to work with the latest releases of Azure Storage, and
based on the explanations of @brettsam, you can simply write a custom
CustomQueueProcessorFactory to create a new CloudQueueMessage in
CopyMessageToPoisonQueueAsync.
namespace ConsoleApplication1
{
using Microsoft.Azure.WebJobs.Host.Queues;
using Microsoft.WindowsAzure.Storage.Queue;
using System.Threading;
using System.Threading.Tasks;
public class CustomQueueProcessorFactory : IQueueProcessorFactory
{
public QueueProcessor Create(QueueProcessorFactoryContext context)
{
return new CustomQueueProcessor(context);
}
private class CustomQueueProcessor : QueueProcessor
{
public CustomQueueProcessor(QueueProcessorFactoryContext context)
: base(context)
{
}
protected override Task CopyMessageToPoisonQueueAsync(CloudQueueMessage message, CloudQueue poisonQueue, CancellationToken cancellationToken)
{
var newMessage = new CloudQueueMessage(message.Id, message.PopReceipt);
newMessage.SetMessageContent(message.AsBytes);
return base.CopyMessageToPoisonQueueAsync(newMessage, poisonQueue, cancellationToken);
}
}
}
}
Then in your Main, you just have to set the custom queue processor
factory in the job host configuration:
var config = new JobHostConfiguration();
config.Queues.QueueProcessorFactory = new CustomQueueProcessorFactory();
I could get it work with WindowsAzure.Storage 8.1.1 and
Microsoft.Azure.WebJobs 2.0.0. Hope that helps!
对于使用 Azure WebJobs v3.x SDK 的任何人:
在 v3.x 中,hosts.json 不适用于 WebJob。
相反,版本 3.x 使用标准 ASP.NET 核心 API,因此您需要使用 ConfigureWebJobs 方法对其进行配置:
static async Task Main()
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
b.AddAzureStorage(a => {
a.BatchSize = 8;
a.NewBatchThreshold = 4;
a.MaxDequeueCount = 4;
a.MaxPollingInterval = TimeSpan.FromSeconds(15);
});
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
我有一个带有几个 queue-triggered 函数的 Azure webjob。 https://docs.microsoft.com/en-us/azure/app-service-web/websites-dotnet-webjobs-sdk-storage-queues-how-to#config 处的 SDK 文档将 MaxDequeueCount
属性 定义为:
The maximum number of retries before a queue message is sent to a poison queue (default is 5).
但我没有看到这种行为。在我的网络作业中,我有:
JobHostConfiguration config = new JobHostConfiguration();
config.Queues.MaxDequeueCount = 1;
JobHost host = new JobHost(config);
host.RunAndBlock();
然后我有一个 queue-triggered 函数,我在其中抛出异常:
public void ProcessQueueMessage([QueueTrigger("azurewejobtestingqueue")] string item, TextWriter logger)
{
if ( item == "exception" )
{
throw new Exception();
}
}
查看 webjobs 仪表板,我看到 SDK 进行了 5 次尝试(如上所述默认为 5 次):
在第 5 次尝试后,邮件将移至毒物队列。我希望看到 1 次重试(或没有重试?)而不是 5 次。
更新:为 web 应用程序启用了详细的日志记录,并选择将这些日志保存到 Azure blob 容器中。在 azure-jobs-host-archive
容器中找到了一些与我的问题相关的日志。下面的示例显示出列计数为 96 的项目:
{
"Type": "FunctionCompleted",
"EndTime": "2017-02-22T00:07:40.8133081+00:00",
"Failure": {
"ExceptionType": "Microsoft.Azure.WebJobs.Host.FunctionInvocationException",
"ExceptionDetails": "Microsoft.Azure.WebJobs.Host.FunctionInvocationException: Exception while executing function: ItemProcessor.ProcessQueueMessage ---> MyApp.Exceptions.MySpecialAppExceptionType: Exception of type 'MyApp.Exceptions.MySpecialAppExceptionType' was thrown.
},
"ParameterLogs": {},
"FunctionInstanceId": "1ffac7b0-1290-4343-8ee1-2af0d39ae2c9",
"Function": {
"Id": "MyApp.Processors.ItemProcessor.ProcessQueueMessage",
"FullName": "MyApp.Processors.ItemProcessor.ProcessQueueMessage",
"ShortName": "ItemProcessor.ProcessQueueMessage",
"Parameters": [
{
"Type": "QueueTrigger",
"AccountName": "MyStorageAccount",
"QueueName": "stuff-processor",
"Name": "sourceFeedItemQueueItem"
},
{
"Type": "BindingData",
"Name": "dequeueCount"
},
{
"Type": "ParameterDescriptor",
"Name": "logger"
}
]
},
"Arguments": {
"sourceFeedItemQueueItem": "{\"SourceFeedUpdateID\":437530,\"PodcastFeedID\":\"2d48D2sf2\"}",
"dequeueCount": "96",
"logger": null
},
"Reason": "AutomaticTrigger",
"ReasonDetails": "New queue message detected on 'stuff-processor'.",
"StartTime": "2017-02-22T00:07:40.6017341+00:00",
"OutputBlob": {
"ContainerName": "azure-webjobs-hosts",
"BlobName": "output-logs/1ffd3c7b012c043438ed12af0d39ae2c9.txt"
},
"ParameterLogBlob": {
"ContainerName": "azure-webjobs-hosts",
"BlobName": "output-logs/1cf2c1b012sa0d3438ee12daf0d39ae2c9.params.txt"
},
"LogLevel": "Info",
"HostInstanceId": "d1825bdb-d92a-4657-81a4-36253e01ea5e",
"HostDisplayName": "ItemProcessor",
"SharedQueueName": "azure-webjobs-host-490daea03c70316f8aa2509438afe8ef",
"InstanceQueueName": "azure-webjobs-host-d18252sdbd92a4657d1a436253e01ea5e",
"Heartbeat": {
"SharedContainerName": "azure-webjobs-hosts",
"SharedDirectoryName": "heartbeats/490baea03cfdfd0416f8aa25aqr438afe8ef",
"InstanceBlobName": "zd1825bdbdsdgga465781a436q53e01ea5e",
"ExpirationInSeconds": 45
},
"WebJobRunIdentifier": {
"WebSiteName": "myappengine",
"JobType": "Continuous",
"JobName": "ItemProcessor",
"RunId": ""
}
}
不过,我进一步寻找的是日志,这些日志会向我显示处理成功(并因此从队列中删除)或因异常而失败并放入毒物队列的特定队列项目的详细信息.到目前为止,我还没有找到任何显示该细节的日志。上面输出中引用的日志文件不包含此类数据。
更新 2:查看了我的毒药队列的状态,它似乎是确凿的证据,但我太笨了,无法将 2 和 2 放在一起。查看下面队列的屏幕截图,您可以在其中多次看到带有 ID(左列)431210
的消息。它多次出现的事实告诉我,原始队列中的消息失败不正确。
我怀疑这是因为您实际上 运行 不是您认为自己在 Azure 中的二进制文件。这个也让我陷入了困境。
当您 运行 在 Azure 上触发 WebJobs 时,发布新版本的 WebJob 不会导致立即卸载旧的触发 WebJob 并启动新的 WebJob。如果您查看 WebJob 日志,我怀疑您在重新发布时不会看到重新启动。
这是因为默认情况下,Kudu 会将所有 WebJob 文件复制到临时目录并执行它们。来自 Kudu WebJob docs:
The WebJob is copied to a temporary directory under %TEMP%\jobs{job type}{job name}{random name} and will run from there This option prevents the original WebJob binaries from being locked which might cause issues redeploying the WebJob. For example updating an .exe file that is currently running.
我在确保新发布的触发 WebJob 实际上是 运行 方面取得的唯一成功是执行以下操作:
登录到 Kudu 控制台。是 https://yourappname.scm.azurewebsites.net。您将使用与登录 Azure 门户时相同的凭据。
登录后,单击顶部的 Process Explorer 菜单选项。找到当前 运行 的 WebJob 进程,然后将其终止。
FTP 到您的 Web 应用程序。浏览到包含您的 WebJob 代码的目录,然后将其删除。它应该在 /app_data/jobs/triggered/[您的网络作业名称].
下
然后我跳到门户,通过 Web 应用程序管理浏览到托管 WebJob 的 blade,单击 WebJobs 菜单选项,并确认旧的 WebJob 不再存在那里。
从 Visual Studio 发布我的新 WebJob。
这应该可以保证您是 运行 您发布的代码。希望这可以帮助。
MaxDequeueCount 属性 如果我配置它,它对我来说工作正常。
所以很奇怪它对你不起作用。当我设置
config.Queues.MaxDequeueCount = 2;
然后我得到了预期的结果请参考截图。
我们也可以使用dequeueCount
来控制重试次数。以下是不尝试的demo代码
public void ProcessQueueMessage([QueueTrigger("queue")] string item, int dequeueCount, TextWriter logger)
{
if (dequeueCount == 1)
{
if (item == "exception")
{
throw new Exception();
}
logger.WriteLine($"NewMsge: {item}");
Console.WriteLine($"NewMsge: {item}");
}
}
日志信息请参考截图
我看到同样的事情,消息超过了最大出队计数。稍后我会 post 更多详细信息,但我也看到似乎有非常大的数字最终进入了毒药队列。所以我怀疑它在 5 之后添加到毒物队列中,但是尝试更多最终导致毒物队列中有很多(数百个)。
如果您仍在寻找答案,我们尝试了列出的一些答案但没有成功。事实证明这是 Storage sdk (WindowsAzure.Storage) 和 Webjob sdk (Microsoft.Azure.WebJobs) 的版本问题。为了修复它,我们最终不得不将我们的存储 sdk 版本降级到 7.2.1(我们最近升级到 8.1.1)。根据下面的文章,工程师们现在已经意识到了这些问题,并希望尽快修复它:
如 Rob W 所述,使用 WindowsAzure.Storage > 7.1.2 时存在此问题。该问题显然已在 issue #1141 中修复,但尚未发布。
贡献者asifferman has shared a code snippet in a comment post on issue #985。这似乎可以解决问题(对我来说效果很好)。
在 link rot 的情况下,为了满足 SO 规则,这里是 post 以及代码片段:
For those (like me) who cannot wait the next release to get the WebJobs SDK to work with the latest releases of Azure Storage, and based on the explanations of @brettsam, you can simply write a custom CustomQueueProcessorFactory to create a new CloudQueueMessage in CopyMessageToPoisonQueueAsync.
namespace ConsoleApplication1
{
using Microsoft.Azure.WebJobs.Host.Queues;
using Microsoft.WindowsAzure.Storage.Queue;
using System.Threading;
using System.Threading.Tasks;
public class CustomQueueProcessorFactory : IQueueProcessorFactory
{
public QueueProcessor Create(QueueProcessorFactoryContext context)
{
return new CustomQueueProcessor(context);
}
private class CustomQueueProcessor : QueueProcessor
{
public CustomQueueProcessor(QueueProcessorFactoryContext context)
: base(context)
{
}
protected override Task CopyMessageToPoisonQueueAsync(CloudQueueMessage message, CloudQueue poisonQueue, CancellationToken cancellationToken)
{
var newMessage = new CloudQueueMessage(message.Id, message.PopReceipt);
newMessage.SetMessageContent(message.AsBytes);
return base.CopyMessageToPoisonQueueAsync(newMessage, poisonQueue, cancellationToken);
}
}
}
}
Then in your Main, you just have to set the custom queue processor factory in the job host configuration:
var config = new JobHostConfiguration();
config.Queues.QueueProcessorFactory = new CustomQueueProcessorFactory();
I could get it work with WindowsAzure.Storage 8.1.1 and Microsoft.Azure.WebJobs 2.0.0. Hope that helps!
对于使用 Azure WebJobs v3.x SDK 的任何人:
在 v3.x 中,hosts.json 不适用于 WebJob。
相反,版本 3.x 使用标准 ASP.NET 核心 API,因此您需要使用 ConfigureWebJobs 方法对其进行配置:
static async Task Main()
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
b.AddAzureStorage(a => {
a.BatchSize = 8;
a.NewBatchThreshold = 4;
a.MaxDequeueCount = 4;
a.MaxPollingInterval = TimeSpan.FromSeconds(15);
});
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}