Skip to content
This repository has been archived by the owner on Jun 12, 2024. It is now read-only.

Commit

Permalink
Exit early on error (NethermindEth#4220) (NethermindEth#4658)
Browse files Browse the repository at this point in the history
* Exit early on error (NethermindEth#4220)

Exit early on error in steps except for step with "mustInitialize" set to false.

* Fix hanging on exit

* Fix exitcode not forwarded

* Rollback unintended commit

* Trying to invoke build

* Fix build

Co-authored-by: Amirul Ashraf <asdacap@gmail.com>
  • Loading branch information
2 people authored and Andrew-Pohl committed Oct 7, 2022
1 parent cd98a4a commit b23de0a
Show file tree
Hide file tree
Showing 14 changed files with 199 additions and 106 deletions.
10 changes: 6 additions & 4 deletions src/Nethermind/Nethermind.Api/Extensions/IPlugin.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
//
// The Nethermind library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
//
// The Nethermind library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.
//
//

using System;
using System.Threading.Tasks;
Expand All @@ -33,5 +33,7 @@ public interface INethermindPlugin : IAsyncDisposable
Task InitNetworkProtocol();

Task InitRpcModules();

bool MustInitialize { get => false; }
}
}
3 changes: 3 additions & 0 deletions src/Nethermind/Nethermind.Config/ExitCodes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ namespace Nethermind.Config;

public static class ExitCodes
{
public const int Ok = 0;
public const int GeneralError = 1;

// config errors 100...199
public const int NoEngineModule = 100;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
// The Nethermind library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The Nethermind library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.
//

namespace Nethermind.Core.Exceptions;

public interface IExceptionWithExitCode
{
int ExitCode { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
// The Nethermind library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The Nethermind library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.
//

using System;

namespace Nethermind.Core.Exceptions;

public class InvalidConfigurationException: Exception, IExceptionWithExitCode
{
public InvalidConfigurationException(string message, int exitCode): base(message)
{
ExitCode = exitCode;
}

public int ExitCode { get; }
}
77 changes: 45 additions & 32 deletions src/Nethermind/Nethermind.Init/Steps/EthereumStepsManager.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
//
// The Nethermind library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
//
// The Nethermind library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.

Expand Down Expand Up @@ -135,40 +135,13 @@ private void RunOneRoundOfInitialization(CancellationToken cancellationToken)

if (_logger.IsDebug) _logger.Debug($"Executing step: {stepInfo}");

Stopwatch stopwatch = Stopwatch.StartNew();
stepInfo.Stage = StepInitializationStage.Executing;
Task task = step.Execute(cancellationToken);
startedThisRound++;
Task continuationTask = task.ContinueWith(t =>
{
stopwatch.Stop();
if (t.IsFaulted && step.MustInitialize)
{
if (_logger.IsError) _logger.Error(
$"Step {step.GetType().Name.PadRight(24)} failed after {stopwatch.ElapsedMilliseconds}ms",
t.Exception);
}
else if (t.IsFaulted)
{
if (_logger.IsWarn) _logger.Warn(
$"Step {step.GetType().Name.PadRight(24)} failed after {stopwatch.ElapsedMilliseconds}ms");
}
else
{
if (_logger.IsDebug) _logger.Debug(
$"Step {step.GetType().Name.PadRight(24)} executed in {stopwatch.ElapsedMilliseconds}ms");
}
stepInfo.Stage = StepInitializationStage.Complete;
_autoResetEvent.Set();
if (_logger.IsDebug) _logger.Debug($"{step.GetType().Name.PadRight(24)} complete");
});
Task task = ExecuteStep(step, stepInfo, cancellationToken);

if (step.MustInitialize)
{
_allPending.Enqueue(continuationTask);
_allPending.Enqueue(task);
}
else
{
Expand All @@ -186,6 +159,46 @@ private void RunOneRoundOfInitialization(CancellationToken cancellationToken)
}
}

private async Task ExecuteStep(IStep step, StepInfo stepInfo, CancellationToken cancellationToken)
{
Stopwatch stopwatch = Stopwatch.StartNew();
try
{
await step.Execute(cancellationToken);

if (_logger.IsDebug)
_logger.Debug(
$"Step {step.GetType().Name.PadRight(24)} executed in {stopwatch.ElapsedMilliseconds}ms");
}
catch (Exception exception)
{
if (step.MustInitialize)
{
if (_logger.IsError)
_logger.Error(
$"Step {step.GetType().Name.PadRight(24)} failed after {stopwatch.ElapsedMilliseconds}ms",
exception);

throw;
}

if (_logger.IsWarn)
{
_logger.Warn(
$"Step {step.GetType().Name.PadRight(24)} failed after {stopwatch.ElapsedMilliseconds}ms {exception}");
}
}
finally
{
stopwatch.Stop();

stepInfo.Stage = StepInitializationStage.Complete;
_autoResetEvent.Set();

if (_logger.IsDebug) _logger.Debug($"{step.GetType().Name.PadRight(24)} complete");
}
}

private IStep? CreateStepInstance(StepInfo stepInfo)
{
IStep? step = null;
Expand Down
8 changes: 5 additions & 3 deletions src/Nethermind/Nethermind.Init/Steps/InitializeNodeStats.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
//
// The Nethermind library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
//
// The Nethermind library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.

Expand Down Expand Up @@ -43,5 +43,7 @@ public Task Execute(CancellationToken _)

return Task.CompletedTask;
}

public bool MustInitialize => false;
}
}
9 changes: 5 additions & 4 deletions src/Nethermind/Nethermind.Init/Steps/InitializePlugins.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
//
// The Nethermind library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
//
// The Nethermind library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.
//
//

using System;
using System.Diagnostics;
Expand Down Expand Up @@ -53,6 +53,7 @@ public async Task Execute(CancellationToken cancellationToken)
catch (Exception e)
{
if (logger.IsError) logger.Error($"Failed to initialize plugin {plugin.Name} by {plugin.Author}", e);
if (plugin.MustInitialize) throw;
}
}
}
Expand Down
8 changes: 5 additions & 3 deletions src/Nethermind/Nethermind.Init/Steps/StartLogProducer.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
//
// The Nethermind library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
//
// The Nethermind library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.

Expand Down Expand Up @@ -38,5 +38,7 @@ public Task Execute(CancellationToken cancellationToken)
_api.Publishers.Add(logPublisher);
return Task.CompletedTask;
}

public bool MustInitialize => false;
}
}
10 changes: 6 additions & 4 deletions src/Nethermind/Nethermind.Init/Steps/StartMonitoring.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
//
// The Nethermind library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
//
// The Nethermind library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.
//
//

using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -74,4 +74,6 @@ await _api.MonitoringService.StartAsync().ContinueWith(x =>
logger.Info("Grafana / Prometheus metrics are disabled in configuration");
}
}

public bool MustInitialize => false;
}
25 changes: 4 additions & 21 deletions src/Nethermind/Nethermind.Merge.Plugin.Test/MergePluginTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
using Nethermind.Consensus.Clique;
using Nethermind.Consensus.Producers;
using Nethermind.Core;
using Nethermind.Core.Exceptions;
using Nethermind.Core.Test.Builders;
using Nethermind.Db;
using Nethermind.JsonRpc;
Expand Down Expand Up @@ -80,7 +81,7 @@ public void Setup()
Epoch = CliqueConfig.Default.Epoch,
Period = CliqueConfig.Default.BlockPeriod
};
_plugin = new MergePlugin(new EnvironmentExitMock());
_plugin = new MergePlugin();

_consensusPlugin = new();
}
Expand Down Expand Up @@ -140,7 +141,7 @@ public async Task InitThrowsWhenNoEngineApiUrlsConfigured(bool jsonRpcEnabled, b

await _plugin.Invoking((plugin) => plugin.Init(_context))
.Should()
.ThrowAsync<InvalidOperationException>();
.ThrowAsync<InvalidConfigurationException>();
}

[Test]
Expand Down Expand Up @@ -187,25 +188,7 @@ public async Task InitThrowExceptionIfBodiesAndReceiptIsDisabled(bool downloadBo
}
else
{
await invocation.Should().ThrowAsync<InvalidOperationException>();
}
}

private class EnvironmentExitMock : IEnvironment
{
public string GetEnvironmentVariable(string variableName)
{
throw new NotImplementedException();
}

public IDictionary GetEnvironmentVariables()
{
throw new NotImplementedException();
}

public void Exit(int exitCode)
{
throw new InvalidOperationException($"Exit with exitCode: {exitCode}");
await invocation.Should().ThrowAsync<InvalidConfigurationException>();
}
}
}
Expand Down
Loading

0 comments on commit b23de0a

Please sign in to comment.