public NotificationHelper(IOptions <EventSourcingOnAzureOptions> options,
                                  INameResolver nameResolver,
                                  ILogger logger)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }


            if (nameResolver == null)
            {
                throw new ArgumentNullException(nameof(nameResolver));
            }

            _options = options;

            if (null != logger)
            {
                _logger = logger;
            }

            // Get the event grid instance connection details to use
            this.eventGridKeyValue      = options.Value.EventGridKeyValue;
            this.eventGridTopicEndpoint = options.Value.EventGridTopicEndpoint;

            if (nameResolver.TryResolveWholeString(options.Value.EventGridTopicEndpoint, out var endpoint))
            {
                this.eventGridTopicEndpoint = endpoint;
            }

            if (nameResolver.TryResolveWholeString(options.Value.EventGridKeyValue, out var keyvalue))
            {
                this.eventGridKeyValue = keyvalue;
            }

            if (!string.IsNullOrEmpty(this.eventGridTopicEndpoint))
            {
                // The HTTP responses that are not fatal and deserve a retry
                // (NOT HttpStatusCode.ServiceUnavailable)
                HttpStatusCode[] retryStatusCode = new HttpStatusCode[] {
                    HttpStatusCode.RequestTimeout,
                    HttpStatusCode.InternalServerError,
                    HttpStatusCode.GatewayTimeout,
                    HttpStatusCode.NetworkAuthenticationRequired
                };

                // Start the message handler, with these retry statuses set
                this.HttpMessageHandler = new HttpRetryMessageHandler(
                    new HttpClientHandler(),
                    options.Value.EventGridPublishRetryCount,
                    options.Value.EventGridPublishRetryInterval,
                    retryStatusCode);
            }
        }
예제 #2
0
        public static async Task <IStorageAccount> GetStorageAccountAsync(this IStorageAccountProvider provider, ParameterInfo parameter, CancellationToken cancellationToken, INameResolver nameResolver = null)
        {
            if (provider == null)
            {
                throw new ArgumentNullException("provider");
            }

            string connectionStringName = GetAccountOverrideOrNull(parameter);

            if (string.IsNullOrEmpty(connectionStringName))
            {
                connectionStringName = ConnectionStringNames.Storage;
            }

            if (nameResolver != null)
            {
                string resolved = null;
                if (nameResolver.TryResolveWholeString(connectionStringName, out resolved))
                {
                    connectionStringName = resolved;
                }
            }

            IStorageAccount account = await provider.TryGetAccountAsync(connectionStringName, cancellationToken);

            ValidateStorageAccount(account, connectionStringName);
            return(account);
        }
        internal WebPubSubTriggerAttribute GetResolvedAttribute(WebPubSubTriggerAttribute attribute)
        {
            // Try resolve and throw exception if not able to find one.
            if (!_nameResolver.TryResolveWholeString(attribute.Hub, out var hub))
            {
                throw new ArgumentException($"Failed to resolve substitute configure: {attribute.Hub}, please add.");
            }
            if (!_nameResolver.TryResolveWholeString(attribute.EventName, out var eventName))
            {
                throw new ArgumentException($"Failed to resolve substitute configure: {attribute.EventName}, please add.");
            }

            return(new WebPubSubTriggerAttribute(
                       hub,
                       attribute.EventType,
                       eventName));
        }
        public LifeCycleNotificationHelper(
            DurableTaskOptions config,
            INameResolver nameResolver,
            EndToEndTraceHelper traceHelper)
        {
            this.config      = config ?? throw new ArgumentNullException(nameof(config));
            this.traceHelper = traceHelper ?? throw new ArgumentNullException(nameof(traceHelper));

            if (nameResolver == null)
            {
                throw new ArgumentNullException(nameof(nameResolver));
            }

            this.eventGridKeyValue      = nameResolver.Resolve(config.EventGridKeySettingName);
            this.eventGridTopicEndpoint = config.EventGridTopicEndpoint;
            if (nameResolver.TryResolveWholeString(config.EventGridTopicEndpoint, out var endpoint))
            {
                this.eventGridTopicEndpoint = endpoint;
            }

            if (!string.IsNullOrEmpty(this.eventGridTopicEndpoint))
            {
                if (!string.IsNullOrEmpty(config.EventGridKeySettingName))
                {
                    this.useTrace = true;

                    var retryStatusCode = config.EventGridPublishRetryHttpStatus?
                                          .Where(x => Enum.IsDefined(typeof(HttpStatusCode), x))
                                          .Select(x => (HttpStatusCode)x)
                                          .ToArray()
                                          ?? Array.Empty <HttpStatusCode>();

                    // Currently, we support Event Grid Custom Topic for notify the lifecycle event of an orchestrator.
                    // For more detail about the Event Grid, please refer this document.
                    // Post to custom topic for Azure Event Grid
                    // https://docs.microsoft.com/en-us/azure/event-grid/post-to-custom-topic
                    this.HttpMessageHandler = config.NotificationHandler ?? new HttpRetryMessageHandler(
                        new HttpClientHandler(),
                        config.EventGridPublishRetryCount,
                        config.EventGridPublishRetryInterval,
                        retryStatusCode);

                    if (string.IsNullOrEmpty(this.eventGridKeyValue))
                    {
                        throw new ArgumentException($"Failed to start lifecycle notification feature. Please check the configuration values for {config.EventGridKeySettingName} on AppSettings.");
                    }
                }
                else
                {
                    throw new ArgumentException($"Failed to start lifecycle notification feature. Please check the configuration values for {config.EventGridTopicEndpoint} and {config.EventGridKeySettingName}.");
                }
            }
        }
 public static string ResolveTriggerName(ParameterInfo parameter, INameResolver nameResolver, string?triggerName)
 {
     if (triggerName == null)
     {
         MemberInfo method = parameter.Member;
         return(method.GetCustomAttribute <FunctionNameAttribute>()?.Name ?? method.Name);
     }
     else if (nameResolver.TryResolveWholeString(triggerName, out string?resolvedTriggerName))
     {
         return(resolvedTriggerName);
     }
     else
     {
         return(triggerName);
     }
 }
        public EventGridLifeCycleNotificationHelper(
            DurableTaskOptions config,
            INameResolver nameResolver,
            EndToEndTraceHelper traceHelper)
        {
            this.config      = config ?? throw new ArgumentNullException(nameof(config));
            this.traceHelper = traceHelper ?? throw new ArgumentNullException(nameof(traceHelper));

            if (nameResolver == null)
            {
                throw new ArgumentNullException(nameof(nameResolver));
            }

            this.eventGridKeyValue      = nameResolver.Resolve(config.EventGridKeySettingName);
            this.eventGridTopicEndpoint = config.EventGridTopicEndpoint;

            if (nameResolver.TryResolveWholeString(config.EventGridTopicEndpoint, out var endpoint))
            {
                this.eventGridTopicEndpoint = endpoint;
            }

            if (!string.IsNullOrEmpty(this.eventGridTopicEndpoint))
            {
                if (!string.IsNullOrEmpty(config.EventGridKeySettingName))
                {
                    this.useTrace = true;

                    var retryStatusCode = config.EventGridPublishRetryHttpStatus?
                                          .Where(x => Enum.IsDefined(typeof(HttpStatusCode), x))
                                          .Select(x => (HttpStatusCode)x)
                                          .ToArray()
                                          ?? Array.Empty <HttpStatusCode>();

                    if (config.EventGridPublishEventTypes == null || config.EventGridPublishEventTypes.Length == 0)
                    {
                        this.eventGridPublishEventTypes = (OrchestrationRuntimeStatus[])Enum.GetValues(typeof(OrchestrationRuntimeStatus));
                    }
                    else
                    {
                        var startedIndex = Array.FindIndex(config.EventGridPublishEventTypes, x => x == "Started");
                        if (startedIndex > -1)
                        {
                            config.EventGridPublishEventTypes[startedIndex] = OrchestrationRuntimeStatus.Running.ToString();
                        }

                        OrchestrationRuntimeStatus ParseAndvalidateEvents(string @event)
                        {
                            var success = Enum.TryParse(@event, out OrchestrationRuntimeStatus @enum);

                            if (success)
                            {
                                switch (@enum)
                                {
                                case OrchestrationRuntimeStatus.Canceled:
                                case OrchestrationRuntimeStatus.ContinuedAsNew:
                                case OrchestrationRuntimeStatus.Pending:
                                    success = false;
                                    break;

                                default:
                                    break;
                                }
                            }

                            if (!success)
                            {
                                throw new ArgumentException("Failed to start lifecycle notification feature. Unsupported event types detected in 'EventGridPublishEventTypes'. You may only specify one or more of the following 'Started', 'Completed', 'Failed', 'Terminated'.");
                            }

                            return(@enum);
                        }

                        this.eventGridPublishEventTypes = config.EventGridPublishEventTypes.Select(
                            x => ParseAndvalidateEvents(x)).ToArray();
                    }

                    // Currently, we support Event Grid Custom Topic for notify the lifecycle event of an orchestrator.
                    // For more detail about the Event Grid, please refer this document.
                    // Post to custom topic for Azure Event Grid
                    // https://docs.microsoft.com/en-us/azure/event-grid/post-to-custom-topic
                    this.HttpMessageHandler = config.NotificationHandler ?? new HttpRetryMessageHandler(
                        new HttpClientHandler(),
                        config.EventGridPublishRetryCount,
                        config.EventGridPublishRetryInterval,
                        retryStatusCode);

                    if (string.IsNullOrEmpty(this.eventGridKeyValue))
                    {
                        throw new ArgumentException($"Failed to start lifecycle notification feature. Please check the configuration values for {config.EventGridKeySettingName} on AppSettings.");
                    }
                }
                else
                {
                    throw new ArgumentException($"Failed to start lifecycle notification feature. Please check the configuration values for {config.EventGridTopicEndpoint} and {config.EventGridKeySettingName}.");
                }
            }
        }