perf(net): make ElectrumClient's in-flight request cap configurable

MaxInFlight was a hardcoded constant (32); different indexing servers
tolerate different levels of request concurrency before throttling, so
expose it as an optional ConnectAsync parameter instead of requiring a
recompile to tune initial-sync throughput against a given server.
This commit is contained in:
2026-07-19 12:16:11 +02:00
parent d9dd05aa52
commit 6d05a88073
+12 -5
View File
@@ -36,8 +36,12 @@ public sealed class ElectrumClient : IAsyncDisposable
// single segment; this gate avoids flooding the server with thousands of
// simultaneous requests on large wallets → no bursts of -101/-102 nor
// connection drops. Writes still stay pipelined up to this degree.
private const int MaxInFlight = 32;
private readonly SemaphoreSlim _inFlight = new(MaxInFlight, MaxInFlight);
// Configurable per connection (see ConnectAsync): the right value trades off
// initial-sync throughput against how aggressively a given server tolerates
// concurrent requests before throttling — no single constant is right for
// every server, so callers may raise/lower it instead of recompiling.
public const int DefaultMaxInFlight = 32;
private readonly SemaphoreSlim _inFlight;
private long _nextId;
@@ -49,19 +53,22 @@ public sealed class ElectrumClient : IAsyncDisposable
public event Action<string, JsonElement>? NotificationReceived;
public event Action<Exception?>? Disconnected;
private ElectrumClient(TcpClient tcp, Stream stream, string host, int port, bool useSsl)
private ElectrumClient(TcpClient tcp, Stream stream, string host, int port, bool useSsl,
int maxInFlight)
{
_tcp = tcp;
_stream = stream;
Host = host;
Port = port;
UseSsl = useSsl;
_inFlight = new SemaphoreSlim(maxInFlight, maxInFlight);
_readLoop = Task.Run(ReadLoopAsync);
_writeLoop = Task.Run(WriteLoopAsync);
}
public static async Task<ElectrumClient> ConnectAsync(string host, int port, bool useSsl,
CertificatePinStore? pins = null, CancellationToken ct = default)
CertificatePinStore? pins = null, CancellationToken ct = default,
int maxInFlight = DefaultMaxInFlight)
{
var tcp = new TcpClient { NoDelay = true };
try
@@ -90,7 +97,7 @@ public sealed class ElectrumClient : IAsyncDisposable
stream = ssl;
}
var client = new ElectrumClient(tcp, stream, host, port, useSsl);
var client = new ElectrumClient(tcp, stream, host, port, useSsl, maxInFlight);
await client.RequestAsync("server.version", ct, ClientName, ProtocolVersion);
return client;
}