mirror of
https://github.com/AlexMacocian/MTSC.git
synced 2026-07-15 14:59:33 +00:00
Background services implementation (#6)
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
using MTSC.ServerSide.BackgroundServices;
|
||||
|
||||
namespace MTSC.UnitTests.BackgroundServices
|
||||
{
|
||||
public sealed class IteratingBackgroundService : BackgroundServiceBase
|
||||
{
|
||||
private readonly IteratingService iteratingService;
|
||||
|
||||
public IteratingBackgroundService(IteratingService iteratingService)
|
||||
{
|
||||
this.iteratingService = iteratingService;
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
this.iteratingService.Iterate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using MTSC.ServerSide;
|
||||
|
||||
namespace MTSC.UnitTests.BackgroundServices
|
||||
{
|
||||
public class IteratingService
|
||||
{
|
||||
private readonly Server server;
|
||||
|
||||
public int Iteration { get; private set; } = 0;
|
||||
|
||||
public IteratingService(Server server)
|
||||
{
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public void Iterate()
|
||||
{
|
||||
this.server.Log("Iterating");
|
||||
this.Iteration++;
|
||||
this.server.Log("Iterated");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MTSC.Common.Http;
|
||||
@@ -6,6 +7,7 @@ using MTSC.Exceptions;
|
||||
using MTSC.ServerSide.Handlers;
|
||||
using MTSC.ServerSide.Schedulers;
|
||||
using MTSC.ServerSide.UsageMonitors;
|
||||
using MTSC.UnitTests.BackgroundServices;
|
||||
using MTSC.UnitTests.RoutingModules;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
@@ -56,12 +58,15 @@ namespace MTSC.UnitTests
|
||||
.AddRoute<LongRunningModule>(HttpMessage.HttpMethods.Get, "long-running")
|
||||
.AddRoute<MultipartModule>(HttpMessage.HttpMethods.Post, "multipart")
|
||||
.AddRoute<SomeRoutingModule>(HttpMessage.HttpMethods.Post, "some-module/{someValue}/test/{intValue}/test")
|
||||
.AddRoute<IterationModule>(HttpMessage.HttpMethods.Get, "iteration")
|
||||
.WithFragmentsExpirationTime(TimeSpan.FromMilliseconds(3000))
|
||||
.WithMaximumSize(250000))
|
||||
.AddBackgroundService<IteratingBackgroundService>(interval: TimeSpan.FromSeconds(5))
|
||||
.AddExceptionHandler(new ExceptionConsoleLogger())
|
||||
.SetScheduler(new ParallelScheduler())
|
||||
.WithSslAuthenticationTimeout(TimeSpan.FromMilliseconds(100));
|
||||
Server.ServiceManager.RegisterSingleton<ILogger, ConsoleLogger>();
|
||||
Server.ServiceManager.RegisterSingleton<IteratingService>();
|
||||
Server.RunAsync();
|
||||
}
|
||||
|
||||
@@ -384,6 +389,24 @@ namespace MTSC.UnitTests
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task BackgroundService_GetsPeriodicallyCalled()
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
httpClient.BaseAddress = new Uri("http://localhost:800");
|
||||
var result = await httpClient.GetAsync("iteration");
|
||||
result.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var iteration = int.Parse(await result.Content.ReadAsStringAsync());
|
||||
|
||||
await Task.Delay(5000);
|
||||
|
||||
var result2 = await httpClient.GetAsync("iteration");
|
||||
result2.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var iteration2 = int.Parse(await result2.Content.ReadAsStringAsync());
|
||||
|
||||
Assert.IsTrue(iteration == iteration2 - 1);
|
||||
}
|
||||
|
||||
[ClassCleanup]
|
||||
public static void CleanupServer()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using MTSC.Common.Http;
|
||||
using MTSC.Common.Http.RoutingModules;
|
||||
using MTSC.UnitTests.BackgroundServices;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MTSC.UnitTests.RoutingModules
|
||||
{
|
||||
public sealed class IterationModule : HttpRouteBase
|
||||
{
|
||||
private readonly IteratingService iteratingService;
|
||||
|
||||
public IterationModule(
|
||||
IteratingService iteratingService)
|
||||
{
|
||||
this.iteratingService = iteratingService ?? throw new ArgumentNullException(nameof(iteratingService));
|
||||
}
|
||||
|
||||
public override Task<HttpResponse> HandleRequest(HttpRequestContext request)
|
||||
{
|
||||
var iteration = this.iteratingService.Iteration;
|
||||
|
||||
return Task.FromResult(new HttpResponse
|
||||
{
|
||||
StatusCode = HttpMessage.StatusCodes.OK,
|
||||
BodyString = iteration.ToString()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace MTSC.Common.WebSockets.ClientModules
|
||||
{
|
||||
public sealed class ChatModule : IWebsocketModule
|
||||
{
|
||||
static RNGCryptoServiceProvider rng = new();
|
||||
static readonly RandomNumberGenerator rng = RandomNumberGenerator.Create();
|
||||
#region Public Methods
|
||||
public void SendMessage(WebsocketHandler websocketHandler, string message)
|
||||
{
|
||||
|
||||
+3
-3
@@ -5,13 +5,13 @@
|
||||
<TargetFrameworks>net48;netstandard2.0;netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
|
||||
<ApplicationIcon />
|
||||
<StartupObject />
|
||||
<Version>4.8.0</Version>
|
||||
<Version>5.0</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Authors>Alexandru-Victor Macocian</Authors>
|
||||
<Product>MTSC</Product>
|
||||
<Description>Modular TCP Server and Client</Description>
|
||||
<AssemblyVersion>4.8.0.0</AssemblyVersion>
|
||||
<FileVersion>4.8.0.0</FileVersion>
|
||||
<AssemblyVersion>5.0.0.0</AssemblyVersion>
|
||||
<FileVersion>5.0.0.0</FileVersion>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<PackageProjectUrl>https://github.com/AlexMacocian/MTSC</PackageProjectUrl>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MTSC.ServerSide.BackgroundServices
|
||||
{
|
||||
public abstract class AsyncBackgroundServiceBase : BackgroundServiceBase
|
||||
{
|
||||
public override sealed void Execute()
|
||||
{
|
||||
var task = Task.Run(this.ExecuteAsync);
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
public abstract Task ExecuteAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
|
||||
namespace MTSC.ServerSide.BackgroundServices
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for background services.
|
||||
/// These services will be called periodically by the server, the period being defined by the <see cref="BackgroundServiceBase.ActivationInterval"/>.
|
||||
/// </summary>
|
||||
public abstract class BackgroundServiceBase : ISetBackgroundServiceProperties
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="ServerSide.Server"/> containing the <see cref="BackgroundServiceBase"/>.
|
||||
/// </summary>
|
||||
public Server Server { get; private set; }
|
||||
/// <summary>
|
||||
/// Interval between calls from server.
|
||||
/// </summary>
|
||||
public TimeSpan ActivationInterval { get; private set; }
|
||||
/// <summary>
|
||||
/// Last time the <see cref="BackgroundServiceBase"/> was called.
|
||||
/// </summary>
|
||||
public DateTime LastActivationTime { get; private set; }
|
||||
|
||||
public abstract void Execute();
|
||||
|
||||
void ISetBackgroundServiceProperties.SetActivationInterval(TimeSpan activationInterval)
|
||||
{
|
||||
this.ActivationInterval = activationInterval;
|
||||
}
|
||||
void ISetBackgroundServiceProperties.SetLastActivationTime(DateTime dateTime)
|
||||
{
|
||||
this.LastActivationTime = dateTime;
|
||||
}
|
||||
void ISetBackgroundServiceProperties.SetServer(Server server)
|
||||
{
|
||||
this.Server = server ?? throw new ArgumentNullException(nameof(server));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace MTSC.ServerSide.BackgroundServices
|
||||
{
|
||||
internal class BackgroundServiceMetadata
|
||||
{
|
||||
public DateTime LastActivationTime { get; set; }
|
||||
public TimeSpan ActivationInterval { get; set; }
|
||||
public Type RegisteredType { get; set; }
|
||||
public BackgroundServiceBase InitializedService { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MTSC.ServerSide.BackgroundServices
|
||||
{
|
||||
public sealed class BackgroundServicesHolder
|
||||
{
|
||||
private readonly List<BackgroundServiceMetadata> backgroundServices = new();
|
||||
private readonly Server server;
|
||||
|
||||
public BackgroundServicesHolder(Server server)
|
||||
{
|
||||
this.server = server ?? throw new ArgumentNullException();
|
||||
}
|
||||
|
||||
public void RegisterBackgroundService<T>(TimeSpan activationInterval)
|
||||
where T : BackgroundServiceBase
|
||||
{
|
||||
this.server.ServiceManager.RegisterSingleton<T>();
|
||||
this.backgroundServices.Add(new BackgroundServiceMetadata { ActivationInterval = activationInterval, RegisteredType = typeof(T) });
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
foreach(var backgroundServiceMetadata in this.backgroundServices)
|
||||
{
|
||||
this.server.Log($"Initializing background service {backgroundServiceMetadata.RegisteredType.Name}");
|
||||
backgroundServiceMetadata.InitializedService = this.server.ServiceManager.GetService(backgroundServiceMetadata.RegisteredType) as BackgroundServiceBase;
|
||||
(backgroundServiceMetadata.InitializedService as ISetBackgroundServiceProperties).SetServer(this.server);
|
||||
(backgroundServiceMetadata.InitializedService as ISetBackgroundServiceProperties).SetActivationInterval(backgroundServiceMetadata.ActivationInterval);
|
||||
}
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
foreach(var backgroundServiceMetadata in this.backgroundServices)
|
||||
{
|
||||
if (backgroundServiceMetadata.InitializedService is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DateTime.Now - backgroundServiceMetadata.LastActivationTime > backgroundServiceMetadata.ActivationInterval)
|
||||
{
|
||||
this.server.Log($"Activating background service {backgroundServiceMetadata.RegisteredType.Name}");
|
||||
var activationTime = DateTime.Now;
|
||||
backgroundServiceMetadata.LastActivationTime = activationTime;
|
||||
(backgroundServiceMetadata.InitializedService as ISetBackgroundServiceProperties).SetLastActivationTime(activationTime);
|
||||
this.server.Scheduler.ScheduleBackgroundService(backgroundServiceMetadata.InitializedService);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace MTSC.ServerSide.BackgroundServices
|
||||
{
|
||||
internal interface ISetBackgroundServiceProperties
|
||||
{
|
||||
void SetLastActivationTime(DateTime dateTime);
|
||||
void SetServer(Server server);
|
||||
void SetActivationInterval(TimeSpan activationInterval);
|
||||
}
|
||||
}
|
||||
@@ -176,10 +176,10 @@ namespace MTSC.ServerSide.Handlers
|
||||
client.ResetAffinityIfMe(this);
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (Exception)
|
||||
{
|
||||
client.ResetAffinityIfMe(this);
|
||||
throw e;
|
||||
throw;
|
||||
}
|
||||
|
||||
// The message has been parsed. If there was a cache for the current message, remove it.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using MTSC.Common;
|
||||
using MTSC.ServerSide.BackgroundServices;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
@@ -7,6 +8,11 @@ namespace MTSC.ServerSide.Schedulers
|
||||
{
|
||||
public sealed class FireTasksAndForgetScheduler : IScheduler
|
||||
{
|
||||
public void ScheduleBackgroundService(BackgroundServiceBase backgroundServiceBase)
|
||||
{
|
||||
Task.Run(() => backgroundServiceBase.Execute());
|
||||
}
|
||||
|
||||
public void ScheduleHandling(List<(ClientData, IConsumerQueue<Message>)> clientsQueues, Action<ClientData, IConsumerQueue<Message>> messageHandlingProcedure)
|
||||
{
|
||||
foreach(var tuple in clientsQueues)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using MTSC.Common;
|
||||
using MTSC.ServerSide.BackgroundServices;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -7,5 +8,6 @@ namespace MTSC.ServerSide.Schedulers
|
||||
public interface IScheduler
|
||||
{
|
||||
void ScheduleHandling(List<(ClientData, IConsumerQueue<Message>)> clientsQueues, Action<ClientData, IConsumerQueue<Message>> messageHandlingProcedure);
|
||||
void ScheduleBackgroundService(BackgroundServiceBase backgroundServiceBase);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using MTSC.Common;
|
||||
using MTSC.ServerSide.BackgroundServices;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
@@ -7,6 +8,14 @@ namespace MTSC.ServerSide.Schedulers
|
||||
{
|
||||
public sealed class MultiThreadScheduler : IScheduler
|
||||
{
|
||||
public void ScheduleBackgroundService(BackgroundServiceBase backgroundServiceBase)
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
backgroundServiceBase.Execute();
|
||||
}).Start();
|
||||
}
|
||||
|
||||
public void ScheduleHandling(List<(ClientData, IConsumerQueue<Message>)> clientsQueues, Action<ClientData, IConsumerQueue<Message>> messageHandlingProcedure)
|
||||
{
|
||||
foreach((var client, var messageQueue) in clientsQueues)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using MTSC.Common;
|
||||
using MTSC.ServerSide.BackgroundServices;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -8,6 +9,11 @@ namespace MTSC.ServerSide.Schedulers
|
||||
{
|
||||
public sealed class ParallelScheduler : IScheduler
|
||||
{
|
||||
public void ScheduleBackgroundService(BackgroundServiceBase backgroundServiceBase)
|
||||
{
|
||||
Parallel.Invoke(backgroundServiceBase.Execute);
|
||||
}
|
||||
|
||||
public void ScheduleHandling(List<(ClientData, IConsumerQueue<Message>)> clientsQueues, Action<ClientData, IConsumerQueue<Message>> messageHandlingProcedure)
|
||||
{
|
||||
Parallel.Invoke(clientsQueues.Select(tuple => new Action(() => messageHandlingProcedure.Invoke(tuple.Item1, tuple.Item2))).ToArray());
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using MTSC.Common;
|
||||
using MTSC.ServerSide.BackgroundServices;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -6,6 +7,11 @@ namespace MTSC.ServerSide.Schedulers
|
||||
{
|
||||
public sealed class SequentialProcessingScheduler : IScheduler
|
||||
{
|
||||
public void ScheduleBackgroundService(BackgroundServiceBase backgroundServiceBase)
|
||||
{
|
||||
backgroundServiceBase.Execute();
|
||||
}
|
||||
|
||||
public void ScheduleHandling(List<(ClientData, IConsumerQueue<Message>)> clientsQueues, Action<ClientData, IConsumerQueue<Message>> messageHandlingProcedure)
|
||||
{
|
||||
foreach(var tuple in clientsQueues)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using MTSC.Common;
|
||||
using MTSC.ServerSide.BackgroundServices;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
@@ -7,6 +8,12 @@ namespace MTSC.ServerSide.Schedulers
|
||||
{
|
||||
public sealed class TaskAwaiterScheduler : IScheduler
|
||||
{
|
||||
public void ScheduleBackgroundService(BackgroundServiceBase backgroundServiceBase)
|
||||
{
|
||||
(backgroundServiceBase as ISetBackgroundServiceProperties).SetLastActivationTime(DateTime.Now);
|
||||
var task = Task.Run(() => backgroundServiceBase.Execute());
|
||||
}
|
||||
|
||||
public void ScheduleHandling(List<(ClientData, IConsumerQueue<Message>)> clientsQueues, Action<ClientData, IConsumerQueue<Message>> messageHandlingProcedure)
|
||||
{
|
||||
var tasks = new List<Task>();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MTSC.Common;
|
||||
using MTSC.Exceptions;
|
||||
using MTSC.ServerSide.BackgroundServices;
|
||||
using MTSC.ServerSide.Handlers;
|
||||
using MTSC.ServerSide.Listeners;
|
||||
using MTSC.ServerSide.Schedulers;
|
||||
@@ -17,10 +18,11 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
// TODO: Setup basic background services
|
||||
namespace MTSC.ServerSide
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic server class to handle TCP connections.
|
||||
/// Main server class.
|
||||
/// </summary>
|
||||
public sealed class Server
|
||||
{
|
||||
@@ -28,6 +30,7 @@ namespace MTSC.ServerSide
|
||||
private CancellationToken cancellationToken;
|
||||
private bool running;
|
||||
private X509Certificate2 certificate;
|
||||
private readonly BackgroundServicesHolder backgroundServicesHolder;
|
||||
private readonly ProducerConsumerQueue<ClientData> addQueue = new();
|
||||
private readonly List<ClientData> clients = new();
|
||||
private readonly List<ClientData> toRemove = new();
|
||||
@@ -113,6 +116,7 @@ namespace MTSC.ServerSide
|
||||
{
|
||||
this.ServiceManager.RegisterServiceManager();
|
||||
this.ServiceManager.RegisterSingleton<Server, Server>(sp => this);
|
||||
this.backgroundServicesHolder = new(this);
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates an instance of server.
|
||||
@@ -123,6 +127,7 @@ namespace MTSC.ServerSide
|
||||
this.Port = port;
|
||||
this.ServiceManager.RegisterServiceManager();
|
||||
this.ServiceManager.RegisterSingleton<Server, Server>(sp => this);
|
||||
this.backgroundServicesHolder = new(this);
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates an instance of server.
|
||||
@@ -135,6 +140,7 @@ namespace MTSC.ServerSide
|
||||
this.Port = port;
|
||||
this.ServiceManager.RegisterServiceManager();
|
||||
this.ServiceManager.RegisterSingleton<Server, Server>(sp => this);
|
||||
this.backgroundServicesHolder = new(this);
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates an instance of server.
|
||||
@@ -147,6 +153,7 @@ namespace MTSC.ServerSide
|
||||
this.Port = port;
|
||||
this.ServiceManager.RegisterServiceManager();
|
||||
this.ServiceManager.RegisterSingleton<Server, Server>(sp => this);
|
||||
this.backgroundServicesHolder = new(this);
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates an instance of server.
|
||||
@@ -161,6 +168,7 @@ namespace MTSC.ServerSide
|
||||
this.IPAddress = ipAddress;
|
||||
this.ServiceManager.RegisterServiceManager();
|
||||
this.ServiceManager.RegisterSingleton<Server, Server>(sp => this);
|
||||
this.backgroundServicesHolder = new(this);
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
@@ -249,6 +257,18 @@ namespace MTSC.ServerSide
|
||||
return this;
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds a <see cref="BackgroundServiceBase"/> to the server.
|
||||
/// </summary>
|
||||
/// <param name="interval">Interval between ticks.</param>
|
||||
/// <typeparam name="TBackgroundService">Type of the background service.</typeparam>
|
||||
/// <returns>This <see cref="Server"/> object.</returns>
|
||||
public Server AddBackgroundService<TBackgroundService>(TimeSpan interval)
|
||||
where TBackgroundService : BackgroundServiceBase
|
||||
{
|
||||
this.backgroundServicesHolder.RegisterBackgroundService<TBackgroundService>(interval);
|
||||
return this;
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the <see cref="ReadTimeout"/> property.
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
@@ -531,6 +551,11 @@ namespace MTSC.ServerSide
|
||||
toBeRunOnStartup.OnStartup(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize background services.
|
||||
*/
|
||||
this.backgroundServicesHolder.Initialize();
|
||||
|
||||
DateTime startLoopTime;
|
||||
while (this.running)
|
||||
{
|
||||
@@ -614,6 +639,18 @@ namespace MTSC.ServerSide
|
||||
this.TickHandler(handler);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tick background services
|
||||
*/
|
||||
try
|
||||
{
|
||||
this.backgroundServicesHolder.Tick();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
this.HandleException(e);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if there are messages queued to be sent.
|
||||
*/
|
||||
@@ -644,10 +681,7 @@ namespace MTSC.ServerSide
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
foreach (var handler in this.exceptionHandlers)
|
||||
{
|
||||
handler.HandleException(e);
|
||||
}
|
||||
this.HandleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -876,6 +910,8 @@ namespace MTSC.ServerSide
|
||||
}
|
||||
private void HandleException(Exception exception)
|
||||
{
|
||||
this.Log($"Encountered {exception.GetType().Name}");
|
||||
this.LogDebug(exception.ToString());
|
||||
foreach (var exceptionHandler in this.exceptionHandlers)
|
||||
{
|
||||
if (exceptionHandler.HandleException(exception))
|
||||
|
||||
Reference in New Issue
Block a user