using System; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Amazon.CloudWatch; using System.Collections.Concurrent; using TradeIdeasCommon.Models; using Newtonsoft.Json; namespace TradeIdeasCommon.Services.Metrics { public sealed class AwsMetricsService { private readonly ILogger _logger; private readonly IAmazonCloudWatch _cloudWatch; private bool _running = false; private readonly BlockingCollection _bcqPutMetricDataRequests; public AwsMetricsService(ILogger logger, IAmazonCloudWatch cloudWatch) { _logger = logger; _cloudWatch = cloudWatch; _bcqPutMetricDataRequests = new BlockingCollection(new ConcurrentQueue()); //Start the Monitor Worker for AWS Cloud Watch Metrics _running = true; Task.Run(async () => await PutMetricsWorker()); } public async Task PutMetrics(AwsPutMetricsRequest putMetricsRequest) { //This is a fire and forget method with no blocking //The item is enqueued and processed by a worker thread. foreach( var item in putMetricsRequest.PutMetricDataRequest.MetricData) { if (item.TimestampUtc == DateTime.MinValue) item.TimestampUtc = DateTime.UtcNow; } var result = new ServiceResult(); result.Status = _bcqPutMetricDataRequests.TryAdd(putMetricsRequest) ? ServiceResultStatuses.Success : ServiceResultStatuses.ServerError; await Task.CompletedTask; return result; } private async Task PutMetricsWorker() { try { while (_running) { try { if (_bcqPutMetricDataRequests.TryTake(out AwsPutMetricsRequest putMetricsRequest, 1000)) { _logger.LogInformation("Logging Metrics..."); var response = await _cloudWatch.PutMetricDataAsync(putMetricsRequest.PutMetricDataRequest); if ( response.HttpStatusCode != System.Net.HttpStatusCode.OK) _logger.LogWarning($"{putMetricsRequest.RequestId} failed with code:{response.HttpStatusCode} for request:{JsonConvert.SerializeObject(putMetricsRequest)}"); } } catch (Exception ex) { _logger.LogError(ex, ex.Message); } } } catch (Exception ex) { _logger.LogError(ex, ex.Message); } } } }