[#24] Client: Implement pool part1
first iteration - base classes and methods Signed-off-by: Pavel Gross <p.gross@yadro.com>
This commit is contained in:
parent
d1271df207
commit
c9a75ea025
72 changed files with 2786 additions and 468 deletions
137
src/FrostFS.SDK.ClientV2/Poll/ClientWrapper.cs
Normal file
137
src/FrostFS.SDK.ClientV2/Poll/ClientWrapper.cs
Normal file
|
@ -0,0 +1,137 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
// clientWrapper is used by default, alternative implementations are intended for testing purposes only.
|
||||
public class ClientWrapper
|
||||
{
|
||||
private readonly object _lock = new();
|
||||
|
||||
public ClientWrapper(WrapperPrm wrapperPrm)
|
||||
{
|
||||
WrapperPrm = wrapperPrm;
|
||||
StatusMonitor = new ClientStatusMonitor(wrapperPrm.Logger, wrapperPrm.Address, wrapperPrm.ErrorThreshold);
|
||||
|
||||
try
|
||||
{
|
||||
Client = new FrostFSClient(WrapperPrm);
|
||||
StatusMonitor.SetHealthy();
|
||||
}
|
||||
catch (FrostFsException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal FrostFSClient? Client { get; private set; }
|
||||
|
||||
internal WrapperPrm WrapperPrm { get; }
|
||||
|
||||
internal ClientStatusMonitor StatusMonitor { get; }
|
||||
|
||||
internal FrostFSClient? GetClient()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (StatusMonitor.IsHealthy())
|
||||
{
|
||||
return Client;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// dial establishes a connection to the server from the FrostFS network.
|
||||
// Returns an error describing failure reason. If failed, the client
|
||||
// SHOULD NOT be used.
|
||||
internal async Task<string?> Dial(CallContext ctx)
|
||||
{
|
||||
var client = GetClient();
|
||||
|
||||
if (client == null)
|
||||
return "pool client unhealthy";
|
||||
|
||||
var result = await client.Dial(ctx).ConfigureAwait(false);
|
||||
if (!string.IsNullOrEmpty(result))
|
||||
{
|
||||
StatusMonitor.SetUnhealthyOnDial();
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private async Task ScheduleGracefulClose()
|
||||
{
|
||||
if (Client == null)
|
||||
return;
|
||||
|
||||
await Task.Delay((int)WrapperPrm.GracefulCloseOnSwitchTimeout).ConfigureAwait(false);
|
||||
|
||||
Client.Close();
|
||||
}
|
||||
|
||||
// restartIfUnhealthy checks healthy status of client and recreate it if status is unhealthy.
|
||||
// Indicating if status was changed by this function call and returns error that caused unhealthy status.
|
||||
internal async Task<bool> RestartIfUnhealthy(CallContext ctx)
|
||||
{
|
||||
bool wasHealthy;
|
||||
|
||||
try
|
||||
{
|
||||
var prmNodeInfo = new PrmNodeInfo { Context = ctx };
|
||||
var response = await Client!.GetNodeInfoAsync(prmNodeInfo).ConfigureAwait(false);
|
||||
return false;
|
||||
}
|
||||
catch (FrostFsException)
|
||||
{
|
||||
wasHealthy = true;
|
||||
}
|
||||
|
||||
// if connection is dialed before, to avoid routine/connection leak,
|
||||
// pool has to close it and then initialize once again.
|
||||
if (StatusMonitor.IsDialed())
|
||||
{
|
||||
await ScheduleGracefulClose().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
#pragma warning disable CA2000 // Dispose objects before losing scope: will be disposed manually
|
||||
FrostFSClient client = new(WrapperPrm);
|
||||
#pragma warning restore CA2000
|
||||
|
||||
//TODO: set additioanl params
|
||||
var error = await client.Dial(ctx).ConfigureAwait(false);
|
||||
if (!string.IsNullOrEmpty(error))
|
||||
{
|
||||
StatusMonitor.SetUnhealthyOnDial();
|
||||
return wasHealthy;
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
Client = client;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var prmNodeInfo = new PrmNodeInfo { Context = ctx };
|
||||
var res = await client.GetNodeInfoAsync(prmNodeInfo).ConfigureAwait(false);
|
||||
}
|
||||
catch (FrostFsException)
|
||||
{
|
||||
StatusMonitor.SetUnhealthy();
|
||||
return wasHealthy;
|
||||
}
|
||||
|
||||
StatusMonitor.SetHealthy();
|
||||
return !wasHealthy;
|
||||
}
|
||||
|
||||
internal void IncRequests(ulong elapsed, MethodIndex method)
|
||||
{
|
||||
var methodStat = StatusMonitor.Methods[(int)method];
|
||||
|
||||
methodStat.IncRequests(elapsed);
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue