1
0
mirror of https://github.com/RaidMax/IW4M-Admin.git synced 2025-06-07 21:58:06 -05:00

Add command execution backoff/timeout

This commit is contained in:
RaidMax 2024-02-24 18:07:34 -06:00
parent 0f135337a9
commit aa83d88c77
3 changed files with 52 additions and 2 deletions

View File

@ -25,6 +25,7 @@ using Serilog.Context;
using static SharedLibraryCore.Database.Models.EFClient;
using Data.Models;
using Data.Models.Server;
using Humanizer;
using IW4MAdmin.Application.Alerts;
using IW4MAdmin.Application.Commands;
using IW4MAdmin.Application.Plugin.Script;
@ -193,11 +194,47 @@ namespace IW4MAdmin
Command command = null;
if (E.Type == GameEvent.EventType.Command)
{
if (E.Origin is not null)
{
var canExecute = true;
if (E.Origin.CommandExecutionAttempts > 0)
{
var remainingTimeout =
E.Origin.LastCommandExecutionAttempt +
Utilities.GetExponentialBackoffDelay(E.Origin.CommandExecutionAttempts) -
DateTimeOffset.UtcNow;
if (remainingTimeout.TotalSeconds > 0)
{
if (E.Origin.CommandExecutionAttempts < 2 ||
E.Origin.CommandExecutionAttempts % 5 == 0)
{
E.Origin.Tell(_translationLookup["COMMANDS_BACKOFF_MESSAGE"]
.FormatExt(remainingTimeout.Humanize()));
}
canExecute = false;
}
else
{
E.Origin.CommandExecutionAttempts = 0;
}
}
E.Origin.LastCommandExecutionAttempt = DateTimeOffset.UtcNow;
E.Origin.CommandExecutionAttempts++;
if (!canExecute)
{
return;
}
}
try
{
command = await SharedLibraryCore.Commands.CommandProcessing.ValidateCommand(E, Manager.GetApplicationSettings().Configuration(), _commandConfiguration);
}
catch (CommandException e)
{
ServerLogger.LogWarning(e, "Error validating command from event {@Event}",

View File

@ -120,6 +120,11 @@ namespace SharedLibraryCore.Database.Models
[NotMapped]
public string TimeSinceLastConnectionString => (DateTime.UtcNow - LastConnection).HumanizeForCurrentCulture();
public DateTimeOffset LastCommandExecutionAttempt { get; set; } = DateTimeOffset.MinValue;
[NotMapped]
public int CommandExecutionAttempts { get; set; }
[NotMapped]
// this is kinda dirty, but I need localizable level names
public ClientPermission ClientPermission => new ClientPermission

View File

@ -1340,6 +1340,14 @@ namespace SharedLibraryCore
return serviceCollection;
}
public static TimeSpan GetExponentialBackoffDelay(int retryCount, int staticDelay = 5)
{
var maxTimeout = TimeSpan.FromMinutes(2.1);
const double factor = 2.0;
var delay = Math.Min(staticDelay + Math.Pow(factor, retryCount - 1), maxTimeout.TotalSeconds);
return TimeSpan.FromSeconds(delay);
}
public static void ExecuteAfterDelay(TimeSpan duration, Func<CancellationToken, Task> action, CancellationToken token = default) =>
ExecuteAfterDelay((int)duration.TotalMilliseconds, action, token);