0

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

4

1 回答 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 回答