public static OrderWithStatus FromOrder(Order order) { if (order == null) { return(null); } // To simulate a real backend process, we fake status updates based on the amount // of time since the order was placed string statusText; List <Marker> mapMarkers; var dispatchTime = order.CreatedTime.AddSeconds(10); var deliveryDuration = TimeSpan.FromMinutes(1); // Unrealistic, but more interesting to watch int progress = 0; if (DateTime.UtcNow < dispatchTime) { statusText = "Preparing"; progress = 33; mapMarkers = new List <Marker> { ToMapMarker("You", order.DeliveryLocation, showPopup: true) }; } else if (DateTime.UtcNow < dispatchTime + deliveryDuration) { statusText = "Out for delivery"; progress = 66; var startPosition = ComputeStartPosition(order); var proportionOfDeliveryCompleted = Math.Min(1, (DateTime.Now - dispatchTime).TotalMilliseconds / deliveryDuration.TotalMilliseconds); var driverPosition = LatLong.Interpolate(startPosition, order.DeliveryLocation, proportionOfDeliveryCompleted); mapMarkers = new List <Marker> { ToMapMarker("You", order.DeliveryLocation), ToMapMarker("Driver", driverPosition, showPopup: true), }; } else { statusText = "Delivered"; progress = 100; mapMarkers = new List <Marker> { ToMapMarker("Delivery location", order.DeliveryLocation, showPopup: true), }; } return(new OrderWithStatus { Order = order, StatusText = statusText, MapMarkers = mapMarkers, Progress = progress }); }
private async Task ProcessAsync(Order order) { var database = multiplexer.GetDatabase(); var subscriber = multiplexer.GetSubscriber(); var status = new OrderStatus() { Id = order.OrderId, Status = "Preparing", CurrentLocation = null, }; await database.StringSetAsync($"orderstatus-{order.OrderId}", JsonSerializer.Serialize(status, options)); await subscriber.PublishAsync($"orderupdates-{order.OrderId}", JsonSerializer.Serialize(status, options)); await Task.Delay(TimeSpan.FromSeconds(10)); var startPosition = ComputeStartPosition(order); status.Status = "Out for delivery"; status.CurrentLocation = startPosition; await database.StringSetAsync($"orderstatus-{order.OrderId}", JsonSerializer.Serialize(status, options)); await subscriber.PublishAsync($"orderupdates-{order.OrderId}", JsonSerializer.Serialize(status, options)); var stopwatch = Stopwatch.StartNew(); var duration = TimeSpan.FromMinutes(1); while (stopwatch.Elapsed < duration) { var proportionOfDeliveryCompleted = Math.Min(1, stopwatch.Elapsed.TotalMilliseconds / duration.TotalMilliseconds); status.CurrentLocation = LatLong.Interpolate(startPosition, order.DeliveryLocation, proportionOfDeliveryCompleted); await database.StringSetAsync($"orderstatus-{order.OrderId}", JsonSerializer.Serialize(status, options)); await subscriber.PublishAsync($"orderupdates-{order.OrderId}", JsonSerializer.Serialize(status, options)); await Task.Delay(TimeSpan.FromSeconds(3)); } status.Status = "Delivered"; await database.StringSetAsync($"orderstatus-{order.OrderId}", JsonSerializer.Serialize(status, options)); await subscriber.PublishAsync($"orderupdates-{order.OrderId}", JsonSerializer.Serialize(status, options)); logger.LogInformation("Delivered order {OrderId}.", order.OrderId); }
public static OrderWithStatus FromOrder(Order order) { // To simulate a real backend process, we fake status updates based on the amount // of time since the order was placed string statusText; List <Marker> mapMarkers; var dispatchTime = order.CreatedTime.Add(PreparationDuration); if (DateTime.Now < dispatchTime) { statusText = "Preparing"; mapMarkers = new List <Marker> { ToMapMarker("You", order.DeliveryLocation, showPopup: true) }; } else if (DateTime.Now < dispatchTime + DeliveryDuration) { statusText = "Out for delivery"; var startPosition = ComputeStartPosition(order); var proportionOfDeliveryCompleted = Math.Min(1, (DateTime.Now - dispatchTime).TotalMilliseconds / DeliveryDuration.TotalMilliseconds); var driverPosition = LatLong.Interpolate(startPosition, order.DeliveryLocation, proportionOfDeliveryCompleted); mapMarkers = new List <Marker> { ToMapMarker("You", order.DeliveryLocation), ToMapMarker("Driver", driverPosition, showPopup: true), }; } else { statusText = "Delivered"; mapMarkers = new List <Marker> { ToMapMarker("Delivery location", order.DeliveryLocation, showPopup: true), }; } return(new OrderWithStatus { Order = order, StatusText = statusText, MapMarkers = mapMarkers, }); }
protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.LogInformation("Pizza delivery worker running at: {time}", DateTimeOffset.Now); while (!stoppingToken.IsCancellationRequested) { try { var msg = await PizzaDeliveryQueue.GetMessageAsync(); if (msg != null) { var order = JsonConvert.DeserializeObject <Order>(msg.AsString); using (IServiceScope scope = _serviceProvider.CreateScope()) { // Save the order to the DB var context = scope.ServiceProvider.GetRequiredService <PizzaStoreContext>(); order.Status = "Out for delivery"; context.Orders.Attach(order); await context.SaveChangesAsync(); await PizzaDeliveryQueue.DeleteMessageAsync(msg); _logger.LogInformation($"Order {order.OrderId} out for delivery"); // Send delivery status var startPosition = order.CurrentLocation; var dispatchTime = DateTime.Now; var deliveryDuration = TimeSpan.FromSeconds(20); var proportionOfDeliveryCompleted = 0d; var httpClient = new HttpClient { BaseAddress = new Uri("https://localhost:5001") }; var client = GrpcClient.Create <PizzaOrderStatusClient>(httpClient); Ack ack; while (proportionOfDeliveryCompleted < 1) { proportionOfDeliveryCompleted = Math.Min(1, (DateTime.Now - dispatchTime).TotalMilliseconds / deliveryDuration.TotalMilliseconds); _logger.LogInformation($"Proportion complete for order {order.OrderId}: {proportionOfDeliveryCompleted}"); order.CurrentLocation = LatLong.Interpolate(startPosition, order.DeliveryLocation, proportionOfDeliveryCompleted); ack = await client.SendStatusAsync(order.ToStatusUpdate()); _logger.LogInformation($"Status update ack: {ack.Message}"); await Task.Delay(1000, stoppingToken); } order.Status = "Delivered"; context.Orders.Attach(order); await context.SaveChangesAsync(); _logger.LogInformation($"Order {order.OrderId} delivered"); ack = await client.SendStatusAsync(order.ToStatusUpdate()); _logger.LogInformation($"Status update ack: {ack.Message}"); } } } catch (Exception ex) { _logger.LogError(ex, $"Error deliverying pizza order: {ex.Message}"); } // Mandatory Pizza delivery worker break await Task.Delay(1000, stoppingToken); } }
protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.LogInformation("Pizza delivery worker running at: {time}", DateTimeOffset.Now); while (!stoppingToken.IsCancellationRequested) { try { var msg = await PizzaDeliveryQueue.GetMessageAsync(); if (msg != null) { var order = JsonConvert.DeserializeObject <Order>(msg.AsString); using (IServiceScope scope = _serviceProvider.CreateScope()) { // Save the order to the DB var context = scope.ServiceProvider.GetRequiredService <PizzaStoreContext>(); order.Status = "Out for delivery"; context.Orders.Attach(order); var result = await context.SaveChangesAsync(); await PizzaDeliveryQueue.DeleteMessageAsync(msg); _logger.LogInformation($"Order {order.RequestId} out for delivery"); // Send delivery status var startPosition = order.CurrentLocation; var dispatchTime = DateTime.Now; var deliveryDuration = TimeSpan.FromSeconds(20); var proportionOfDeliveryCompleted = 0d; StatusUpdate statusUpdate = order.ToStatusUpdate(); PizzaOrderStatusClient client = default; HttpClient httpClient = default; Ack ack = default; var httpHandler = new HttpClientHandler(); // Return `true` to allow certificates that are untrusted/invalid httpHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; httpHandler.UseProxy = false; while (proportionOfDeliveryCompleted == 0d) { if (DateTime.Now > dispatchTime.Add(deliveryDuration)) { proportionOfDeliveryCompleted -= 1; } } { proportionOfDeliveryCompleted = Math.Min(1, (DateTime.Now - dispatchTime).TotalMilliseconds / deliveryDuration.TotalMilliseconds); _logger.LogInformation($"Proportion complete for order {order.RequestId}: {proportionOfDeliveryCompleted}"); order.CurrentLocation = LatLong.Interpolate(startPosition, order.DeliveryLocation, proportionOfDeliveryCompleted); var channel = GrpcChannel.ForAddress("https://localhost:54001/", new GrpcChannelOptions { HttpHandler = httpHandler }); client = new PizzaOrderStatusClient(channel); //httpClient = new HttpClient { BaseAddress = new Uri(UriString) }; //httpClient.Timeout = new TimeSpan(0, 3, 0); //client = GrpcClient.Create<PizzaOrderStatusClient>(httpClient); ack = await client.SendStatusAsync(statusUpdate); _logger.LogInformation($"Status update ack: {ack.Message}"); await Task.Delay(1000, stoppingToken); } order.Status = "Delivered"; context.Orders.Attach(order); await context.SaveChangesAsync(); _logger.LogInformation($"Order {order.RequestId} delivered"); ack = await client.SendStatusAsync(order.ToStatusUpdate()); _logger.LogInformation($"Status update ack: {ack.Message}"); } } } catch (Exception ex) { _logger.LogError(ex, $"Error deliverying pizza order: {ex.Message}"); } // Mandatory Pizza delivery worker break await Task.Delay(1000, stoppingToken); } }