我在 .net 核心中有一个现有的 webjob(V3.0),它有一个由手动触发器调用的函数,基本上是由一个 webhook。我想向同一个 webjob 添加另一个函数,该函数应该每 20 分钟在 Timer 触发器上调用一次。是否可以将这两者都放在同一个网络作业中。如果可能的话,我需要做什么主机配置。我尝试浏览 Microsoft 的文档,但几乎没有任何关于具有多个触发器的主机配置部分的文档
问问题
485 次
1 回答
0
是的,但是您的函数需要由 Azure 存储中的某个对象(例如队列)触发。此代码可能比您可能需要的更多。我所有的服务都实现了一个自定义接口 IServiceInvoker。我的 CTOR 要求
IEnumerable<IServiceInvoker>
获得所有服务。然后我要么使用常量,要么使用传入的值来确定要运行的服务。因为我只希望一个函数一直运行,所以我使用传入 String.Empty 的 Singleton 属性。我的队列上也有以下设置
b.AddAzureStorage(a =>
{
a.BatchSize = 1;
a.NewBatchThreshold = 1;
a.MaxDequeueCount = 1;
a.MaxPollingInterval = TimeSpan.FromSeconds(60);
a.VisibilityTimeout = TimeSpan.FromSeconds(60);
});
最后我发现在测试过程中我有时需要关闭或关闭更多功能,因此需要使用 ServiceConfigurationProvider 类。
代码示例如下我删除了相当多的代码,所以 YMMV
public static async Task Main(string[] args)
{
await CreateHostBuilder(args).Build().RunAsync();
}
更多代码
public class Functions
{
/// <summary>
/// This scopes the singleton attribute to each individual function rather than the entire host
/// </summary>
const String SCOPESINGLETONTOFUNCTION = "";
readonly ILogger<Functions> _logger;
readonly Dictionary<String, IServiceInvoker> _services;
readonly IConfiguration _configuration;
private Functions()
{
_services = new Dictionary<string, IServiceInvoker>();
}
public Functions(IEnumerable<IServiceInvoker> services, ILoggerFactory loggerFactory, IServiceProvider serviceProvider, IConfiguration configuration) : this()
{
_logger = loggerFactory.CreateLogger<Functions>();
foreach (var service in services)
{
_services.Add(service.ServiceIdentifier, service);
}
_configuration = configuration;
}
[Disable(typeof(ServiceConfigurationProvider))]
[Singleton(SCOPESINGLETONTOFUNCTION)]
public async Task TimerTriggerFunction([TimerTrigger("%TimerTriggerFunctionExpression%")]TimerInfo myTimer, CancellationToken cancellationToken)
{
try
{
if (_services.TryGetValue("ServiceName", out IServiceInvoker serviceToInvoke))
{
await serviceToInvoke.InvokeServiceAsync(null, cancellationToken, false);
}
}
catch (Exception ex)
{
_logger?.LogError(ex, $"Unhandled exception occurred in method:'{nameof(TimerTriggerFunction)}'");
}
}
[Disable(typeof(ServiceConfigurationProvider))]
[Singleton(SCOPESINGLETONTOFUNCTION)]
public async Task ServiceInvokerQueueFunction([QueueTrigger("%ServiceInvokerQueueName%", Connection = "AzureWebJobsStorage")] ServiceInvokerMessage serviceInvokerMessage, CancellationToken cancellationToken)
{
if (serviceInvokerMessage is null || String.IsNullOrEmpty(serviceInvokerMessage.ServiceIdentifier))
{
_logger?.LogError("The queue message received in the ServiceInvokerQueueFunction could not be serialized into a ServiceInvokerMessage instance.");
}
else
{
Boolean serviceExists = _services.TryGetValue(serviceInvokerMessage.ServiceIdentifier, out IServiceInvoker serviceToInvoke);
if (serviceExists)
{
try
{
await serviceToInvoke.InvokeServiceAsync(null, cancellationToken, true);
}
catch (Exception exception)
{
_logger?.LogError(exception, $"Unhandled exception occurred in method:'{nameof(ServiceInvokerQueueFunction)}' for service:'{serviceInvokerMessage.ServiceIdentifier}'");
}
}
}
}
[Disable(typeof(ServiceConfigurationProvider))]
[Singleton(SCOPESINGLETONTOFUNCTION)]
public async Task RecordQueueFunction([QueueTrigger("%RecordQueueName%", Connection = "RecordConnectString")] string message, CancellationToken cancellationToken)
{
{
_logger?.LogInformation(message);
try
{
if (_services.TryGetValue("ServiceName", out IServiceInvoker serviceToInvoke))
{
await serviceToInvoke.InvokeServiceAsync(message, cancellationToken, false);
}
}
catch (Exception ex)
{
_logger?.LogError(ex, $"Unhandled exception occurred in method:'{nameof(RecordQueueFunction)}'");
throw;
}
}
}
}
public class ServiceConfigurationProvider
{
readonly IConfiguration _configuration;
public ServiceConfigurationProvider(IConfiguration configuration)
{
_configuration = configuration;
}
public bool IsDisabled(MethodInfo method)
{
Boolean returnValue = false;
String resultConfiguration = _configuration[$"{method.Name}Disable"];
if (!String.IsNullOrEmpty(resultConfiguration))
{
Boolean.TryParse(resultConfiguration, out returnValue);
}
return returnValue;
}
}
于 2019-10-22T20:27:45.010 回答