一个webjob是否可以具有计时器触发功能以及手动触发功能

时间:2019-10-17 07:12:44

标签: azure azure-webjobs azure-webjobssdk azure-webjobs-triggered

我在.net核心中有一个现有的webjob(V3.0),其功能由手动触发器(本质上是由Webhook)调用。我想向应该每20分钟在Timer触发器上调用的同一webjob中添加另一个函数。是否可以将它们都放在同一个webjob中。如果可能的话,我需要做什么主机配置。我尝试浏览Microsoft的文档,但几乎没有关于具有多个触发器的主机配置部分的文档

1 个答案:

答案 0 :(得分: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;
    }
}