private async Task HeartbeatCheck() { Logger.Log(LogLevel.Info, $"Heartbeat check - {_apiRequestService.totalCustomAPIRequestsMade} API requests made ({_apiRequestService.totalCustomAPIRequestsMadeSinceHeartbeat} requests in the last hour) - starting server checks."); // thread-safe reset 30m counter Interlocked.Exchange(ref _apiRequestService.totalCustomAPIRequestsMadeSinceHeartbeat, 0); // do a global companion status check to see if the API is down or if something else is wrong CustomApiStatus globalCompanionStatusRequestResult = GetCompanionApiStatus().Result; // if companion is in maintenance, reset timer and don't do anything else if (globalCompanionStatusRequestResult == CustomApiStatus.UnderMaintenance) { AdjustHeartbeatTimer(); Logger.Log(LogLevel.Info, $"The SE API is down for maintenance at the moment. Trying again later."); return; } // log any error responses that aren't logged-out or maintenance issues & send DM to bot owner // this is deprecated now as any errors from the APIRequestService will give us logs and DMs already /* * if (globalCompanionStatusRequestResult != CustomApiStatus.OK && globalCompanionStatusRequestResult != CustomApiStatus.NotLoggedIn && globalCompanionStatusRequestResult != CustomApiStatus.UnderMaintenance) * { * Logger.Log(LogLevel.Info, $"SE API error - received error: {globalCompanionStatusRequestResult}."); * * var dm = await _discord.GetUser(ulong.Parse(_config["discordBotOwnerId"])).GetOrCreateDMChannelAsync(); * await dm.SendMessageAsync($"Something's wrong with the API - received error: {globalCompanionStatusRequestResult}."); * } */ // figure out each server's login status serverLoginStatusTracker.Clear(); var tasks = Task.Run(() => Parallel.ForEach((Worldss[])Enum.GetValues(typeof(Worldss)), parallelOptions, async server => { CustomApiStatus serverStatusRequestResult = GetCompanionApiStatus(server.ToString()).Result; bool serverLoggedIn = false; if (serverStatusRequestResult == CustomApiStatus.OK) // logged in, continue processing { serverLoggedIn = true; } else if (serverStatusRequestResult == CustomApiStatus.NotLoggedIn) // not logged in, continue processing { serverLoggedIn = false; } // runs if servers are logged in or not logged in, will not run if api error or maintenance serverLoginStatusTracker.TryAdd(server, serverLoggedIn); })); await Task.WhenAll(tasks); // get how many servers are logged in currently var serverLoggedInCount = serverLoginStatusTracker.Count(x => x.Value == true); Logger.Log(LogLevel.Info, $"{serverLoggedInCount} of {serverLoginStatusTracker.Count} game servers are logged in. "); // if any servers are down, try to log them in // use a random delay to avoid potential bans if (serverLoggedInCount != serverLoginStatusTracker.Count) { int errorCount = 0; foreach (var serverStatus in serverLoginStatusTracker.Where(x => x.Value == false)) { var server = serverStatus.Key; Logger.Log(LogLevel.Info, $"Logging into {server}..."); var loginResult = await _apiRequestService.LoginToCompanionApi(server.ToString()); Logger.Log(LogLevel.Info, $"Login to {server} was {(loginResult ? "successful" : "unsuccessful")}."); if (!loginResult) { errorCount++; // increment on unsuccessful logins } await Task.Delay(_rng.Next(5000, 10000)); // random delay between 5-10 seconds } Logger.Log(LogLevel.Info, $"Login process completed with {errorCount} error(s)."); } AdjustHeartbeatTimer(); }