public static async Task RunAsync([TimerTrigger("0 * 6-15 * * 1-5")] TimerInfo timer, ILogger log) { log.LogInformation($"Park integration function executed at: {DateTime.Now}"); var watch = Stopwatch.StartNew(); var parkingSessions = await GetParkingSessions(2, log); log.LogInformation($"Parking sessions retrived from Park API. ({watch.ElapsedMilliseconds}ms)"); var licensePlates = parkingSessions .Where(s => s.start > DateTime.UtcNow.AddMinutes(-5)) .Select(s => s.vehicle.normalized_licence_plate.ToUpper()) .ToList(); log.LogMetric("VehicleArrived", parkingSessions.Count(s => s.start > DateTime.UtcNow.AddMinutes(-1))); if (licensePlates.Count == 0) { log.LogInformation($"No new vehicles have arrived. Exiting. ({watch.ElapsedMilliseconds}ms)"); return; } log.LogInformation($"{licensePlates.Count} vehicles have arrived in the last 5 minutes. ({watch.ElapsedMilliseconds}ms)"); // Get reservations from SQL database where the car has just arrived var reservations = await _context.Reservation .Include(r => r.User) .Where(r => r.StartDate.Date == DateTime.Today && r.State == State.SubmittedNotActual && licensePlates.Contains(r.VehiclePlateNumber)) .ToListAsync(); if (reservations.Count == 0) { log.LogInformation($"No reservations found where notification should be sent. Exiting. ({watch.ElapsedMilliseconds}ms)"); return; } log.LogInformation($"Found {reservations.Count} reservations. Starting notification sending. ({watch.ElapsedMilliseconds}ms)"); // Send notifications foreach (var reservation in reservations) { reservation.State = State.ReminderSentWaitingForKey; await _context.SaveChangesAsync(); log.LogInformation($"Reservation state updated to ReminderSentWaitingForKey for reservation with id: {reservation.Id}. ({watch.ElapsedMilliseconds}ms)"); if (reservation.User == null) { throw new Exception($"Failed to load user with id: {reservation.UserId}"); } var email = new Email { To = reservation.User.Email, Subject = "Welcome in the office! Don't forget to drop off your key!", Body = $@"Welcome {reservation.User.FirstName}, I just noticed that you've arrived! 👀 Don't forget to leave the key at the reception and <a href='https://carwashu.azurewebsites.net'>confirm drop-off & vehicle location by clicking here</a>! If don't want to get email reminders in the future, you can <a href='https://carwashu.azurewebsites.net/settings'>disable it in the settings</a>." }; switch (reservation.User.NotificationChannel) { case NotificationChannel.Disabled: log.LogInformation($"Notifications are not enabled for the user with id: {reservation.User.Id}."); break; case NotificationChannel.NotSet: case NotificationChannel.Email: await NotificationService.SendEmailReminder(reservation, email); log.LogInformation($"Email notification was sent to the user ({reservation.User.Id}) about the reservation with id: {reservation.Id}. ({watch.ElapsedMilliseconds}ms)"); break; case NotificationChannel.Push: try { var notification = new Notification { Title = "Welcome! 🙋", Body = "I just noticed that you've arrived! 👀 Don't forget to leave the key at the reception and confirm vehicle location!", Tag = NotificationTag.Reminder, RequireInteraction = true, Actions = new List <NotificationAction> { new NotificationAction { Action = "confirm-dropoff", Title = "Confirm drop-off" } } }; await NotificationService.SendPushReminder(reservation, _context, notification); log.LogInformation($"Push notification was sent to the user ({reservation.User.Id}) about the reservation with id: {reservation.Id}. ({watch.ElapsedMilliseconds}ms)"); } catch (Exception e) { log.LogError(e, "Push notification cannot be sent. Failover to email."); await NotificationService.SendEmailReminder(reservation, email); log.LogInformation($"Email notification was sent to the user ({reservation.User.Id}) about the reservation with id: {reservation.Id}. ({watch.ElapsedMilliseconds}ms)"); } break; default: throw new ArgumentOutOfRangeException(); } // Send message to ServiceBus which is monitored by the bot, who will ping the user await NotificationService.SendBotReminderMessage(reservation, BotNotificationQueueName); log.LogInformation($"Bot reminder was sent to the user ({reservation.User.Id}) about the reservation with id: {reservation.Id}. ({watch.ElapsedMilliseconds}ms)"); } log.LogMetric("VehicleArrivedNotificationSent", reservations.Count); log.LogInformation("All reminders have been sent successfully."); watch.Stop(); }