public static void Load()
        {
            //required
            if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("MONGO_HOST")))
            {
                throw new Exception("MONGO_HOST is not defined");
            }

            if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("IOT_API")))
            {
                throw new Exception("IOT_API is not defined");
            }

            //optional
            if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("CACHING")))
            {
                if (int.TryParse(Environment.GetEnvironmentVariable("CACHING"), out var val) && val == 0)
                {
                    UseCache = false;
                }
            }

            if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("MONGO_DB")))
            {
                MongoDatabase = Environment.GetEnvironmentVariable("MONGO_DB");
            }

            if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("MONGO_PORT")))
            {
                int.TryParse(Environment.GetEnvironmentVariable("MONGO_PORT"), out _mongoPort);
            }

            if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TIMEOUT")))
            {
                int.TryParse(Environment.GetEnvironmentVariable("TIMEOUT"), out WebClientTimeout);
            }

            if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DEVICE_RETRIES")))
            {
                int.TryParse(Environment.GetEnvironmentVariable("DEVICE_RETRIES"), out DeviceRetries);
            }

            //load
            _mongoHost = Environment.GetEnvironmentVariable("MONGO_HOST");
            IotApiUrl  = Environment.GetEnvironmentVariable("IOT_API");

            if (UseCache)
            {
                ScheduleRepository.BuildCache();
                Console.WriteLine("[Configuration] Configured to use in-memory cache.");
            }

            Console.WriteLine($"[Configuration] Configured to use mongo @ {MongoDbUrl}");
            Console.WriteLine($"[Configuration] Configured to use IOT-API @ {IotApiUrl}");
        }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation("Worker started at: {time}", DateTime.Now);

            while (!stoppingToken.IsCancellationRequested)
            {
                var now = new TimeSpan(DateTime.Now.TimeOfDay.Hours, DateTime.Now.TimeOfDay.Minutes,
                                       DateTime.Now.TimeOfDay.Seconds);

                Parallel.ForEach(ScheduleRepository.GetRecords().FindAll(x => x.ShouldRun(now)), scheduleObj =>
                {
                    _logger.LogInformation($"Schedule {scheduleObj.Id} running at: {DateTime.Now}");

                    Parallel.ForEach(scheduleObj.Devices, deviceObj =>
                    {
                        var retry = 1;
                        while (true)
                        {
                            try
                            {
                                WebClient.Get(deviceObj.ActionUrl);
                                return;
                            }
                            catch (Exception ex)
                            {
                                _logger.LogError(
                                    $"scheduleId: {scheduleObj.Id}, deviceId: {deviceObj.DeviceId}, " +
                                    $"attempt: {retry}/{AppConfiguration.DeviceRetries}, error: {ex.Message}");

                                if (retry >= AppConfiguration.DeviceRetries)
                                {
                                    return;
                                }

                                Thread.Sleep(1000 * retry * 5);
                                retry++;
                            }
                        }
                    });
                });

                await Task.Delay(1000, stoppingToken);
            }
        }