public async Task EvaluateAsync(MetricQuery query, CancellationToken cancellation = default)
        {
            var options = _optionsProvider.Value;

            var timeout  = query.Timeout.GetValueOrDefault(options.Metrics.Evaluation.Timeout);
            var interval = query.Interval.GetValueOrDefault(options.Metrics.Evaluation.Interval);

            try
            {
                _logger.LogInformation("Starting evaluation of query '{Query}'", query.Name);

                var result = await _queryExecutor.ExecuteAsync(query, timeout, cancellation);

                await _metricsWriter.WriteAsync(query, result, cancellation);
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Query '{Query}' evaluation failed with exception", query.Name);
            }
            finally
            {
                _logger.LogInformation("Query '{Query}' evaluated. Next evaluation on '{NextOccurence}'", query.Name, (DateTime.Now + interval));

                // Re-schedule
                _jobClient.Schedule <ScheduledMetricsEvaluator>(
                    e => e.EvaluateAsync(query, cancellation), interval);
            }
        }
        public async Task Invoke(HttpContext context,
                                 IMetricQueriesProvider queriesProvider,
                                 IOptions <ExporterOptions> optionsProvider,
                                 IMetricQueryExecutor queryExecutor,
                                 IMetricsWriter metricsWriter,
                                 ILogger <OndemandMetricsEvaluationMiddleware> logger)
        {
            var options     = optionsProvider.Value;
            var defaultMode = options.Metrics.Evaluation.Mode;

            var queries = await queriesProvider.GetAsync(context.RequestAborted);

            var tasks = queries.Select(q =>
            {
                if (q.EvaluationMode == MetricsEvaluationMode.Scheduled)
                {
                    return(Task.CompletedTask);
                }

                if (!q.EvaluationMode.HasValue && defaultMode == MetricsEvaluationMode.Scheduled)
                {
                    return(Task.CompletedTask);
                }

                return(Task.Run(async() =>
                {
                    try
                    {
                        logger.LogInformation($"Executing on-demand query '{q.Name}'");

                        var timeout = q.Timeout.GetValueOrDefault(options.Metrics.Evaluation.Timeout);
                        var result = await queryExecutor.ExecuteAsync(q, timeout, context.RequestAborted);

                        await metricsWriter.WriteAsync(q, result, context.RequestAborted);

                        logger.LogInformation($"Executed on-demand query '{q.Name}'");
                    }
                    catch (OperationCanceledException)
                    {
                        // Ignore
                    }
                    catch (Exception e)
                    {
                        logger.LogError(e, $"Unable to write metric for query '{q.Name}'");
                    }
                }, context.RequestAborted));
            });

            await Task.WhenAll(tasks);

            await _next(context);
        }