Example #1
0
        public static async Task Run([TimerTrigger("*/10 * * * *")] TimerInfo timer, ILogger log)
        {
            log.LogInformation($"Reminder function executed at: {DateTime.Now}");
            var watch = Stopwatch.StartNew();

            // Get reservations from SQL database
            var reservations = await _context.Reservation
                               .Include(r => r.User)
                               .Where(r => r.State == State.SubmittedNotActual && r.StartDate.Date == DateTime.Today)
                               .ToListAsync();

            // Cannot use normal LINQ as dates are not in UTC in database. TODO: refactor database to use UTC based times
            reservations = reservations
                           .Where(r => r.StartDate.AddMinutes(MinutesBeforeReservationToSendReminder * -1) < DateTime.Now.ToLocalTime() && DateTime.Now.ToLocalTime() < r.StartDate)
                           .ToList();

            if (reservations.Count == 0)
            {
                log.LogInformation($"No reservations found where reminder should be sent. Exiting. ({watch.ElapsedMilliseconds}ms)");
                return;
            }

            log.LogInformation($"Found {reservations.Count} reservations. Starting reminder sending. ({watch.ElapsedMilliseconds}ms)");

            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 = "CarWash reminder",
                    Body    = $@"Hi {reservation.User.FirstName}, 
It's time 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 = "CarWash reminder",
                            Body  = "It's time 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, BotReminderQueueName);

                log.LogInformation($"Bot reminder was sent to the user ({reservation.User.Id}) about the reservation with id: {reservation.Id}. ({watch.ElapsedMilliseconds}ms)");
            }

            log.LogInformation("All reminders have been sent successfully.");
            watch.Stop();
        }
Example #2
0
        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();
        }