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:
parent
0f135337a9
commit
aa83d88c77
@ -25,6 +25,7 @@ using Serilog.Context;
|
|||||||
using static SharedLibraryCore.Database.Models.EFClient;
|
using static SharedLibraryCore.Database.Models.EFClient;
|
||||||
using Data.Models;
|
using Data.Models;
|
||||||
using Data.Models.Server;
|
using Data.Models.Server;
|
||||||
|
using Humanizer;
|
||||||
using IW4MAdmin.Application.Alerts;
|
using IW4MAdmin.Application.Alerts;
|
||||||
using IW4MAdmin.Application.Commands;
|
using IW4MAdmin.Application.Commands;
|
||||||
using IW4MAdmin.Application.Plugin.Script;
|
using IW4MAdmin.Application.Plugin.Script;
|
||||||
@ -193,11 +194,47 @@ namespace IW4MAdmin
|
|||||||
Command command = null;
|
Command command = null;
|
||||||
if (E.Type == GameEvent.EventType.Command)
|
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
|
try
|
||||||
{
|
{
|
||||||
command = await SharedLibraryCore.Commands.CommandProcessing.ValidateCommand(E, Manager.GetApplicationSettings().Configuration(), _commandConfiguration);
|
command = await SharedLibraryCore.Commands.CommandProcessing.ValidateCommand(E, Manager.GetApplicationSettings().Configuration(), _commandConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (CommandException e)
|
catch (CommandException e)
|
||||||
{
|
{
|
||||||
ServerLogger.LogWarning(e, "Error validating command from event {@Event}",
|
ServerLogger.LogWarning(e, "Error validating command from event {@Event}",
|
||||||
|
@ -120,6 +120,11 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
[NotMapped]
|
[NotMapped]
|
||||||
public string TimeSinceLastConnectionString => (DateTime.UtcNow - LastConnection).HumanizeForCurrentCulture();
|
public string TimeSinceLastConnectionString => (DateTime.UtcNow - LastConnection).HumanizeForCurrentCulture();
|
||||||
|
|
||||||
|
public DateTimeOffset LastCommandExecutionAttempt { get; set; } = DateTimeOffset.MinValue;
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public int CommandExecutionAttempts { get; set; }
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
// this is kinda dirty, but I need localizable level names
|
// this is kinda dirty, but I need localizable level names
|
||||||
public ClientPermission ClientPermission => new ClientPermission
|
public ClientPermission ClientPermission => new ClientPermission
|
||||||
|
@ -1340,6 +1340,14 @@ namespace SharedLibraryCore
|
|||||||
return serviceCollection;
|
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) =>
|
public static void ExecuteAfterDelay(TimeSpan duration, Func<CancellationToken, Task> action, CancellationToken token = default) =>
|
||||||
ExecuteAfterDelay((int)duration.TotalMilliseconds, action, token);
|
ExecuteAfterDelay((int)duration.TotalMilliseconds, action, token);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user