Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix faulty AddLogger in LoggingBus #6028

Merged
merged 10 commits into from Jul 27, 2022

Conversation

Arkatufus
Copy link
Contributor

Exception handling inside AddLogger is wrong

Copy link
Member

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have some questions and one minor requested change

src/core/Akka/Event/LoggingBus.cs Outdated Show resolved Hide resolved
src/core/Akka/Event/LoggingBus.cs Show resolved Hide resolved
@Aaronontheweb
Copy link
Member

@Arkatufus this will need to be sent to v1.5 as well?

@Arkatufus
Copy link
Contributor Author

@Aaronontheweb yeah, I'll make a port when this is done

@Arkatufus
Copy link
Contributor Author

This is the original fix:
a155dcc#diff-d271e591ce53138713aa0d7b825006f40bc2ed5591cd8cb00d7247d7f4ea900fR110-R132

It was made because AddLogger Ask timed out, throwing an AggregateException instead of an AskTimeoutException which was the exception that was expected.

@Arkatufus
Copy link
Contributor Author

@Aaronontheweb
I've decided to change how loggers are loaded, all loggers are loaded asynchronously now. A warning will be emitted for each late responders if they didn't respond within the alloted timeout time.
The con with this approach is that the Ask task will be awaited forever for throwing logger actors, since we do not have a way to trap this inside LoggingBus, but this is basically what happens with the old implementation, a detached task with no timeout.

foreach (var strLoggerType in loggerTypes)
{
var loggerType = Type.GetType(strLoggerType);
if (loggerType == null)
{
throw new ConfigurationException($@"Logger specified in config cannot be found: ""{strLoggerType}""");
Publish(new Error(null, logName, GetType(), $@"Logger specified in config cannot be found: ""{strLoggerType}"""));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We log an error instead of stopping the ActorSystem when a logger type can not be found

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you consider a logger to be critical infrastructure, isn't this a bad idea? i.e. if I don't have visibility into how my service runs at a basic level, how can I be sure it's working correctly?

I'd probably leave the old fail-fast mechanic in-place, which should be even rarer now with the changes in Akka.Hosting.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is different than the logger taking too long to startup - nothing is necessarily wrong with the users' configuration in that case. But in this case, the user's config is 100% wrong and they must fix it. That's why throwing an error here is a good idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, I'll bring the exception code back

AddLogger(system, loggerType, logName);
}

if (!Task.WaitAll(_startupState.Keys.ToArray(), timeout))
Copy link
Contributor Author

@Arkatufus Arkatufus Jul 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will wait for all loggers to be ready here, limiting the time to the timeout period.
The pro of this is that, instead of waiting for a timeout period for each loggers, we only wait once for everything, all logger Ask operation are performed concurrently.

{
throw new ConfigurationException($"Logger [{strLoggerType}] specified in config cannot be loaded: {ex}", ex);
Publish(new Warning(logName, GetType(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We log a warning if any of the Ask-ed loggers hasn't replied after the Wait

@@ -164,46 +173,68 @@ internal void StopDefaultLoggers(ActorSystem system)
Publish(new Debug(SimpleName(this), GetType(), $"Shutting down: {Logging.SimpleName(system.Settings.StdoutLogger)} started"));
}

// Cancel all pending logger initialization tasks
_shutdownCts.Cancel(false);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the mechanism to shutdown all pending Ask if they're still in progress even when the ActorSystem is shutting down.


_startupState[askTask] = new LoggerStartInfo(loggerName, loggerType, logger);
askTask.ContinueWith(t =>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We process all Ask result with a continuation here

Copy link
Member

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has some issues

foreach (var strLoggerType in loggerTypes)
{
var loggerType = Type.GetType(strLoggerType);
if (loggerType == null)
{
throw new ConfigurationException($@"Logger specified in config cannot be found: ""{strLoggerType}""");
Publish(new Error(null, logName, GetType(), $@"Logger specified in config cannot be found: ""{strLoggerType}"""));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you consider a logger to be critical infrastructure, isn't this a bad idea? i.e. if I don't have visibility into how my service runs at a basic level, how can I be sure it's working correctly?

I'd probably leave the old fail-fast mechanic in-place, which should be even rarer now with the changes in Akka.Hosting.

_startupState[askTask] = new LoggerStartInfo(loggerName, loggerType, logger);
askTask.ContinueWith(t =>
{
var info = _startupState[t];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not safe to do this in a continuation, since this is now shared mutable state.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd keep the rest of the continuation but basically just purge the _startupState after the Task.WaitAll.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be safe since this is the only class where it is modified and there is no cross-pollination, each task handles its own continuation and have their own Task as their key.
We had to held on to _startupState because of the possibility that some loggers are not ready after the Task.WaitAll and they needed to retrieve their info. Would it be safe to use closure instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the dictionary, changed it to closure. Just needed the logger name for logging purposes outside of the Task continuation

foreach (var strLoggerType in loggerTypes)
{
var loggerType = Type.GetType(strLoggerType);
if (loggerType == null)
{
throw new ConfigurationException($@"Logger specified in config cannot be found: ""{strLoggerType}""");
Publish(new Error(null, logName, GetType(), $@"Logger specified in config cannot be found: ""{strLoggerType}"""));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is different than the logger taking too long to startup - nothing is necessarily wrong with the users' configuration in that case. But in this case, the user's config is 100% wrong and they must fix it. That's why throwing an error here is a good idea.

Copy link
Member

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Aaronontheweb
Copy link
Member

@Arkatufus needs a backport to v1.5

@Aaronontheweb Aaronontheweb merged commit c8b46b4 into akkadotnet:v1.4 Jul 27, 2022
Arkatufus added a commit to Arkatufus/akka.net that referenced this pull request Jul 28, 2022
* Fix faulty AddLogger in LoggingBus

* Ignore logger async start setting, not relevant anymore

* Simplify unit test

* Send Stop instead of PoisonPill

* Make loggers load asynchronously by default

* Change logging back to exceptions

* Remove _startupState, use closure instead

Co-authored-by: Aaron Stannard <aaron@petabridge.com>
(cherry picked from commit c8b46b4)
Aaronontheweb pushed a commit that referenced this pull request Jul 28, 2022
* Fix faulty AddLogger in LoggingBus

* Ignore logger async start setting, not relevant anymore

* Simplify unit test

* Send Stop instead of PoisonPill

* Make loggers load asynchronously by default

* Change logging back to exceptions

* Remove _startupState, use closure instead

Co-authored-by: Aaron Stannard <aaron@petabridge.com>
(cherry picked from commit c8b46b4)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants