Skip to content

Commit 39d8076

Browse files
authored
Stop accepting JsonRpc requests during shutdown (#7818)
1 parent 9780259 commit 39d8076

File tree

5 files changed

+26
-3
lines changed

5 files changed

+26
-3
lines changed

src/Nethermind/Nethermind.Config/IProcessExitSource.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public interface IProcessExitSource
1616

1717
public class ProcessExitSource : IProcessExitSource
1818
{
19+
private static readonly CancellationToken _cancelledToken = new(canceled: true);
1920
private CancellationTokenSource _cancellationTokenSource;
2021
private readonly TaskCompletionSource _exitResult = new();
2122

@@ -38,5 +39,5 @@ public void Exit(int exitCode)
3839

3940
public Task ExitTask => _exitResult.Task;
4041

41-
public CancellationToken Token => _cancellationTokenSource.Token;
42+
public CancellationToken Token => _cancellationTokenSource?.Token ?? _cancelledToken;
4243
}

src/Nethermind/Nethermind.JsonRpc/IJsonRpcProcessor.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33

44
using System.Collections.Generic;
55
using System.IO.Pipelines;
6+
using System.Threading;
67

78
namespace Nethermind.JsonRpc;
89

910
public interface IJsonRpcProcessor
1011
{
1112
IAsyncEnumerable<JsonRpcResult> ProcessAsync(PipeReader stream, JsonRpcContext context);
13+
CancellationToken ProcessExit { get; }
1214
}

src/Nethermind/Nethermind.JsonRpc/JsonRpcProcessor.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using System.Threading.Tasks;
1717
using Microsoft.AspNetCore.Connections;
1818
using Microsoft.AspNetCore.Http;
19+
using Nethermind.Config;
1920
using Nethermind.Core.Collections;
2021
using Nethermind.Core.Extensions;
2122
using Nethermind.Core.Resettables;
@@ -30,15 +31,18 @@ public class JsonRpcProcessor : IJsonRpcProcessor
3031
private readonly ILogger _logger;
3132
private readonly IJsonRpcService _jsonRpcService;
3233
private readonly Recorder _recorder;
34+
private readonly IProcessExitSource? _processExitSource;
3335

34-
public JsonRpcProcessor(IJsonRpcService jsonRpcService, IJsonRpcConfig jsonRpcConfig, IFileSystem fileSystem, ILogManager logManager)
36+
public JsonRpcProcessor(IJsonRpcService jsonRpcService, IJsonRpcConfig jsonRpcConfig, IFileSystem fileSystem, ILogManager logManager, IProcessExitSource? processExitSource = null)
3537
{
3638
_logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager));
3739
ArgumentNullException.ThrowIfNull(fileSystem);
3840

3941
_jsonRpcService = jsonRpcService ?? throw new ArgumentNullException(nameof(jsonRpcService));
4042
_jsonRpcConfig = jsonRpcConfig ?? throw new ArgumentNullException(nameof(jsonRpcConfig));
4143

44+
_processExitSource = processExitSource;
45+
4246
if (_jsonRpcConfig.RpcRecorderState != RpcRecorderState.None)
4347
{
4448
if (_logger.IsWarn) _logger.Warn("Enabling JSON RPC diagnostics recorder - this will affect performance and should be only used in a diagnostics mode.");
@@ -47,6 +51,9 @@ public JsonRpcProcessor(IJsonRpcService jsonRpcService, IJsonRpcConfig jsonRpcCo
4751
}
4852
}
4953

54+
public CancellationToken ProcessExit
55+
=> _processExitSource?.Token ?? default;
56+
5057
private (JsonRpcRequest? Model, ArrayPoolList<JsonRpcRequest>? Collection) DeserializeObjectOrArray(JsonDocument doc)
5158
{
5259
JsonValueKind type = doc.RootElement.ValueKind;
@@ -120,6 +127,12 @@ private ArrayPoolList<JsonRpcRequest> DeserializeArray(JsonElement element) =>
120127

121128
public async IAsyncEnumerable<JsonRpcResult> ProcessAsync(PipeReader reader, JsonRpcContext context)
122129
{
130+
if (ProcessExit.IsCancellationRequested)
131+
{
132+
JsonRpcErrorResponse response = _jsonRpcService.GetErrorResponse(ErrorCodes.ResourceUnavailable, "Shutting down");
133+
yield return JsonRpcResult.Single(RecordResponse(response, new RpcReport("Shutdown", 0, false)));
134+
}
135+
123136
reader = await RecordRequest(reader);
124137
long startTime = Stopwatch.GetTimestamp();
125138
CancellationTokenSource timeoutSource = new(_jsonRpcConfig.Timeout);

src/Nethermind/Nethermind.Runner/Ethereum/Steps/StartRpc.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ public async Task Execute(CancellationToken cancellationToken)
5050
jsonRpcService,
5151
jsonRpcConfig,
5252
_api.FileSystem,
53-
_api.LogManager);
53+
_api.LogManager,
54+
_api.ProcessExit);
5455

5556

5657
if (initConfig.WebSocketsEnabled)

src/Nethermind/Nethermind.Runner/JsonRpc/Startup.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IJsonRpc
146146
return;
147147
}
148148

149+
if (jsonRpcProcessor.ProcessExit.IsCancellationRequested)
150+
{
151+
ctx.Response.StatusCode = (int)HttpStatusCode.ServiceUnavailable;
152+
return;
153+
}
154+
149155
if (!jsonRpcUrlCollection.TryGetValue(ctx.Connection.LocalPort, out JsonRpcUrl jsonRpcUrl) ||
150156
!jsonRpcUrl.RpcEndpoint.HasFlag(RpcEndpoint.Http))
151157
{

0 commit comments

Comments
 (0)