Switch to GrpcClientIdentificationService and abolish Redis for Idents (#12)

* add GrpcClientIdentificationService

* remove unnecessary gauges

* set to no retry policy

* initialize metrics

Co-authored-by: Stanley Dimant <root.darkarchon@outlook.com>
This commit is contained in:
rootdarkarchon
2022-10-05 23:10:36 +02:00
committed by GitHub
parent 08b04e14d5
commit 17f26714ce
13 changed files with 373 additions and 209 deletions

View File

@@ -0,0 +1,158 @@
using Grpc.Core;
using MareSynchronosShared.Metrics;
using MareSynchronosShared.Protos;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MareSynchronosServer.Services;
public class GrpcClientIdentificationService : IHostedService
{
private readonly string _shardName;
private readonly ILogger<GrpcClientIdentificationService> _logger;
private readonly IdentificationService.IdentificationServiceClient _grpcIdentClient;
private readonly MareMetrics _metrics;
protected ConcurrentDictionary<string, string> OnlineClients = new(StringComparer.Ordinal);
private bool _grpcIsFaulty = false;
public GrpcClientIdentificationService(ILogger<GrpcClientIdentificationService> logger, IdentificationService.IdentificationServiceClient gprcIdentClient, MareMetrics metrics, IConfiguration configuration)
{
var config = configuration.GetSection("MareSynchronos");
_shardName = config.GetValue("ServerName", "Main");
_logger = logger;
_grpcIdentClient = gprcIdentClient;
_metrics = metrics;
}
public async Task<string?> GetCharacterIdentForUid(string uid)
{
if (OnlineClients.TryGetValue(uid, out string ident))
{
return ident;
}
var result = await InvokeOnGrpc(_grpcIdentClient.GetIdentForUidAsync(new UidMessage { Uid = uid })).ConfigureAwait(false);
if (result == default(CharacterIdentMessage)) return null;
return result.Ident;
}
public async Task<string?> GetServerForUid(string uid)
{
if (OnlineClients.ContainsKey(uid))
{
return _shardName;
}
var result = await InvokeOnGrpc(_grpcIdentClient.GetIdentForUidAsync(new UidMessage { Uid = uid })).ConfigureAwait(false);
if (result == default(CharacterIdentMessage)) return null;
return result.ServerId;
}
public async Task<long> GetOnlineUsers()
{
var result = await InvokeOnGrpc(_grpcIdentClient.GetOnlineUserCountAsync(new ServerMessage())).ConfigureAwait(false);
if (result == default(OnlineUserCountResponse)) return OnlineClients.Count;
return result.Count;
}
public async Task<string?> GetUidForCharacterIdent(string characterIdent)
{
bool existsLocal = OnlineClients.Any(o => string.Equals(o.Value, characterIdent, StringComparison.Ordinal));
if (existsLocal)
{
return OnlineClients.First(c => string.Equals(c.Value, characterIdent, StringComparison.Ordinal)).Key;
}
var result = await InvokeOnGrpc(_grpcIdentClient.GetUidForCharacterIdentAsync(new CharacterIdentMessage { Ident = characterIdent, ServerId = string.Empty })).ConfigureAwait(false);
if (result == default(UidMessage)) return null;
return result.Uid;
}
public async Task MarkUserOffline(string uid)
{
OnlineClients.TryRemove(uid, out _);
_metrics.SetGaugeTo(MetricsAPI.GaugeAuthorizedConnections, OnlineClients.Count);
await ExecuteOnGrpc(_grpcIdentClient.RemoveIdentForUidAsync(new RemoveIdentMessage() { ServerId = _shardName, Uid = uid })).ConfigureAwait(false);
}
public async Task MarkUserOnline(string uid, string charaIdent)
{
OnlineClients[uid] = charaIdent;
_metrics.SetGaugeTo(MetricsAPI.GaugeAuthorizedConnections, OnlineClients.Count);
await ExecuteOnGrpc(_grpcIdentClient.SetIdentForUidAsync(new SetIdentMessage() { Ident = charaIdent, ServerId = _shardName, Uid = uid })).ConfigureAwait(false);
}
public async Task StartAsync(CancellationToken cancellationToken)
{
await ExecuteOnGrpc(_grpcIdentClient.ClearIdentsForServerAsync(new ServerMessage() { ServerId = _shardName })).ConfigureAwait(false);
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await ExecuteOnGrpc(_grpcIdentClient.ClearIdentsForServerAsync(new ServerMessage() { ServerId = _shardName })).ConfigureAwait(false);
}
private async Task<T> InvokeOnGrpc<T>(AsyncUnaryCall<T> toExecute)
{
try
{
var result = await toExecute.ConfigureAwait(false);
await CheckFaultStateAndResend().ConfigureAwait(false);
return result;
}
catch
{
SetGrpcFaulty();
return default;
}
}
private async Task ExecuteOnGrpc<T>(AsyncUnaryCall<T> toExecute)
{
try
{
await toExecute.ConfigureAwait(false);
await CheckFaultStateAndResend().ConfigureAwait(false);
}
catch
{
SetGrpcFaulty();
}
}
private async Task CheckFaultStateAndResend()
{
if (_grpcIsFaulty)
{
_logger.LogInformation("GRPC connection is restored, sending current server idents");
await _grpcIdentClient.ClearIdentsForServerAsync(new ServerMessage() { ServerId = _shardName }).ConfigureAwait(false);
var msg = new ServerIdentMessage();
msg.Idents.AddRange(OnlineClients.Select(c => new SetIdentMessage()
{
Ident = c.Value,
Uid = c.Key,
ServerId = _shardName
}));
await _grpcIdentClient.RecreateServerIdentsAsync(msg).ConfigureAwait(false);
_grpcIsFaulty = false;
}
}
private void SetGrpcFaulty()
{
if (!_grpcIsFaulty)
{
_grpcIsFaulty = true;
_logger.LogWarning("GRPC connection is faulty");
}
}
}

View File

@@ -6,7 +6,6 @@ using MareSynchronos.API;
using MareSynchronosServer.Hubs;
using MareSynchronosShared.Data;
using MareSynchronosShared.Metrics;
using MareSynchronosShared.Services;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@@ -19,14 +18,14 @@ public class SystemInfoService : IHostedService, IDisposable
{
private readonly MareMetrics _mareMetrics;
private readonly IServiceProvider _services;
private readonly IClientIdentificationService _clientIdentService;
private readonly GrpcClientIdentificationService _clientIdentService;
private readonly ILogger<SystemInfoService> _logger;
private readonly IHubContext<MareHub> _hubContext;
private Timer _timer;
private string _shardName;
public SystemInfoDto SystemInfoDto { get; private set; } = new();
public SystemInfoService(MareMetrics mareMetrics, IConfiguration configuration, IServiceProvider services, IClientIdentificationService clientIdentService, ILogger<SystemInfoService> logger, IHubContext<MareHub> hubContext)
public SystemInfoService(MareMetrics mareMetrics, IConfiguration configuration, IServiceProvider services, GrpcClientIdentificationService clientIdentService, ILogger<SystemInfoService> logger, IHubContext<MareHub> hubContext)
{
_mareMetrics = mareMetrics;
_services = services;
@@ -56,7 +55,7 @@ public class SystemInfoService : IHostedService, IDisposable
{
SystemInfoDto = new SystemInfoDto()
{
OnlineUsers = _clientIdentService.GetOnlineUsers().Result,
OnlineUsers = (int)_clientIdentService.GetOnlineUsers().Result,
};
_hubContext.Clients.All.SendAsync(Api.OnUpdateSystemInfo, SystemInfoDto);