-
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add reliability features and refactor internals (#4)
* Add Reliability service * Further updates * Implement IDisposible within the Reliable host * Add docs * Use DI forwarding to strip out excess generics * Typo * Update samples * Testing * Use token to unblock on exit * Minor naming changes * Don't throw on cancel * Update README.md * Listen to console lifetime * Prepare for release * Update README.md * Update description
- Loading branch information
Showing
12 changed files
with
258 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Discord.WebSocket; | ||
using Microsoft.Extensions.Hosting; | ||
using Microsoft.Extensions.Logging; | ||
|
||
// Based on ReliabilityService by Foxbot | ||
namespace Discord.Addons.Hosting.Reliability | ||
{ | ||
internal class ReliableDiscordHost : IDisposable | ||
{ | ||
private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(30); | ||
|
||
private readonly DiscordSocketClient _discord; | ||
private readonly ILogger _logger; | ||
private readonly IHost _host; | ||
private CancellationTokenSource _cts; | ||
|
||
public ReliableDiscordHost(DiscordSocketClient discord, ILogger logger, IHost host) | ||
{ | ||
_cts = new CancellationTokenSource(); | ||
_discord = discord; | ||
_logger = logger; | ||
_host = host; | ||
_logger.LogInformation("Using Discord.Net Reliability service - Host will attempt to restart after a 30 second disconnect"); | ||
|
||
_discord.Connected += ConnectedAsync; | ||
_discord.Disconnected += DisconnectedAsync; | ||
} | ||
|
||
private Task ConnectedAsync() | ||
{ | ||
_logger.LogDebug("Discord client reconnected, resetting cancel token..."); | ||
_cts.Cancel(); | ||
_cts = new CancellationTokenSource(); | ||
_logger.LogDebug("Discord client reconnected, cancel token reset."); | ||
|
||
return Task.CompletedTask; | ||
} | ||
|
||
private Task DisconnectedAsync(Exception _e) | ||
{ | ||
_logger.LogInformation("Discord client disconnected, starting timeout task..."); | ||
_ = Task.Delay(_timeout, _cts.Token).ContinueWith(async _ => | ||
{ | ||
_logger.LogDebug("Timeout expired, continuing to check client state..."); | ||
await CheckStateAsync(); | ||
}); | ||
|
||
return Task.CompletedTask; | ||
} | ||
|
||
private async Task CheckStateAsync() | ||
{ | ||
// Client reconnected, no need to reset | ||
if (_discord.ConnectionState == ConnectionState.Connected) | ||
{ | ||
_logger.LogInformation("Discord client recovered"); | ||
return; | ||
} | ||
|
||
_logger.LogCritical("Client did not reconnect in time, restarting host"); | ||
await _host.StopAsync(); | ||
await _host.StartAsync(); | ||
} | ||
|
||
private void Dispose(bool disposing) | ||
{ | ||
if (disposing) | ||
{ | ||
_logger.LogInformation("Disposing Reliability Service"); | ||
_discord.Connected -= ConnectedAsync; | ||
_discord.Disconnected -= DisconnectedAsync; | ||
_cts?.Cancel(); | ||
_cts?.Dispose(); | ||
} | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
Dispose(true); | ||
GC.SuppressFinalize(this); | ||
} | ||
|
||
~ReliableDiscordHost() | ||
{ | ||
Dispose(false); | ||
} | ||
} | ||
} |
72 changes: 72 additions & 0 deletions
72
Discord.Addons.Hosting/Reliability/ReliableHostExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Discord.WebSocket; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Discord.Addons.Hosting.Reliability | ||
{ | ||
/// <summary> | ||
/// Extends <see cref="IHost"/> with Discord.Net Reliability options. | ||
/// </summary> | ||
public static class ReliableHostExtensions | ||
{ | ||
private static ReliableDiscordHost _reliable; | ||
private static CancellationTokenSource _cts; | ||
|
||
/// <summary> | ||
/// Adds the Reliability Service and Runs the host. This function will only return if <see cref="StopReliablyAsync"/> is called elsewhere. Do not use in combination with <see cref="WithReliability"/> | ||
/// </summary> | ||
/// <param name="host">The host to configure.</param> | ||
public static async Task RunReliablyAsync(this IHost host) | ||
{ | ||
host.WithReliability(); | ||
await host.StartAsync(); | ||
_cts = new CancellationTokenSource(); | ||
|
||
AppDomain.CurrentDomain.ProcessExit += (sender, eventArgs) => | ||
{ | ||
_ = host.StopReliablyAsync(); | ||
}; | ||
Console.CancelKeyPress += (sender, e) => { | ||
e.Cancel = true; | ||
_ = host.StopReliablyAsync(); | ||
}; | ||
|
||
await Task.Delay(-1, _cts.Token).ContinueWith(_ => { }); | ||
} | ||
|
||
/// <summary> | ||
/// FOR ADVANCED USE ONLY: Directly adds the reliability service to the host. This may result in unexpected behaviour. For most situations you should use <see cref="RunReliablyAsync"/> instead | ||
/// </summary> | ||
/// <param name="host">The host to configure.</param> | ||
internal static IHost WithReliability(this IHost host) | ||
{ | ||
if(_reliable != null) | ||
throw new InvalidOperationException("Cannot add Reliability Host, it already exists!"); | ||
|
||
var discord = host.Services.GetRequiredService<DiscordSocketClient>(); | ||
var logger = host.Services.GetRequiredService<ILogger<ReliableDiscordHost>>(); | ||
_reliable = new ReliableDiscordHost(discord, logger, host); | ||
|
||
return host; | ||
} | ||
|
||
/// <summary> | ||
/// Disposes the reliability service and stops the host. For use when <see cref="RunReliablyAsync"/> is used to start the host. | ||
/// </summary> | ||
/// <param name="host">The host to configure.</param> | ||
public static async Task StopReliablyAsync(this IHost host) | ||
{ | ||
if (_reliable == null) | ||
throw new InvalidOperationException("Reliable host is null. Shutdown the host normally with StopAsync instead."); | ||
_reliable.Dispose(); | ||
_reliable = null; | ||
await host.StopAsync(); | ||
_cts.Cancel(); | ||
_cts.Dispose(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.