WIP new shard implementation

This commit is contained in:
Ske
2021-04-29 11:10:19 +02:00
parent a2d2036851
commit 118f2d49a6
28 changed files with 725 additions and 547 deletions

View File

@@ -15,6 +15,7 @@ namespace Myriad.Gateway
private readonly GatewaySettings _gatewaySettings;
private readonly ILogger _logger;
private readonly ConcurrentDictionary<int, Shard> _shards = new();
private ShardIdentifyRatelimiter? _ratelimiter;
public Cluster(GatewaySettings gatewaySettings, ILogger logger)
{
@@ -26,81 +27,35 @@ namespace Myriad.Gateway
public event Action<Shard>? ShardCreated;
public IReadOnlyDictionary<int, Shard> Shards => _shards;
public ClusterSessionState SessionState => GetClusterState();
public User? User => _shards.Values.Select(s => s.User).FirstOrDefault(s => s != null);
public ApplicationPartial? Application => _shards.Values.Select(s => s.Application).FirstOrDefault(s => s != null);
private ClusterSessionState GetClusterState()
public async Task Start(GatewayInfo.Bot info)
{
var shards = new List<ClusterSessionState.ShardState>();
foreach (var (id, shard) in _shards)
shards.Add(new ClusterSessionState.ShardState
{
Shard = shard.ShardInfo,
Session = shard.SessionInfo
});
return new ClusterSessionState {Shards = shards};
var concurrency = GetActualShardConcurrency(info.SessionStartLimit.MaxConcurrency);
_ratelimiter = new(_logger, concurrency);
await Start(info.Url, info.Shards);
}
public async Task Start(GatewayInfo.Bot info, ClusterSessionState? lastState = null)
{
if (lastState != null && lastState.Shards.Count == info.Shards)
await Resume(info.Url, lastState, info.SessionStartLimit.MaxConcurrency);
else
await Start(info.Url, info.Shards, info.SessionStartLimit.MaxConcurrency);
}
public async Task Resume(string url, ClusterSessionState sessionState, int concurrency)
{
_logger.Information("Resuming session with {ShardCount} shards at {Url}", sessionState.Shards.Count, url);
foreach (var shardState in sessionState.Shards)
CreateAndAddShard(url, shardState.Shard, shardState.Session);
await StartShards(concurrency);
}
public async Task Start(string url, int shardCount, int concurrency)
public async Task Start(string url, int shardCount)
{
_logger.Information("Starting {ShardCount} shards at {Url}", shardCount, url);
for (var i = 0; i < shardCount; i++)
CreateAndAddShard(url, new ShardInfo(i, shardCount), null);
CreateAndAddShard(url, new ShardInfo(i, shardCount));
await StartShards(concurrency);
await StartShards();
}
private async Task StartShards(int concurrency)
private async Task StartShards()
{
concurrency = GetActualShardConcurrency(concurrency);
var lastTime = DateTimeOffset.UtcNow;
var identifyCalls = 0;
_logger.Information("Connecting shards...");
foreach (var shard in _shards.Values)
{
if (identifyCalls >= concurrency)
{
var timeout = lastTime + TimeSpan.FromSeconds(5.5);
var delay = timeout - DateTimeOffset.UtcNow;
if (delay > TimeSpan.Zero)
{
_logger.Information("Hit shard concurrency limit, waiting {Delay}", delay);
await Task.Delay(delay);
}
identifyCalls = 0;
lastTime = DateTimeOffset.UtcNow;
}
foreach (var shard in _shards.Values)
await shard.Start();
identifyCalls++;
}
}
private void CreateAndAddShard(string url, ShardInfo shardInfo, ShardSessionInfo? session)
private void CreateAndAddShard(string url, ShardInfo shardInfo)
{
var shard = new Shard(_logger, new Uri(url), _gatewaySettings, shardInfo, session);
var shard = new Shard(_gatewaySettings, shardInfo, _ratelimiter!, url, _logger);
shard.OnEventReceived += evt => OnShardEventReceived(shard, evt);
_shards[shardInfo.ShardId] = shard;