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

FSM: exception in LogTermination changes stopEvent.Reason to Shutdown #3723

Closed
stijnherreman opened this issue Feb 26, 2019 · 5 comments
Closed

Comments

@stijnherreman
Copy link

When stopping an FSM with return Stop(new Failure(null)), at first sight it seems to work. But this actually causes an exception in LogTermination(Reason reason) at

_log.Error(failure.Cause.ToString());

Later on in OnTermination, the type of stopEvent.Reason will be Shutdown instead of Failure.

I'd expect one of these to happen:

  • an ArgumentNullException is thrown when calling new Failure(null)
  • exceptions in LogTermination(...) are caught so the original stop reason is preserved
@eaba
Copy link
Contributor

eaba commented Dec 1, 2020

@Aaronontheweb I have investigated this issue on this branch and here is the fix attempt:

private void Terminate(State<TState, TData> upcomingState)
{
      if (_currentState.StopReason == null)
      {
          var reason = upcomingState.StopReason;

          //if reason is failure and cause is null, here is the best place to fix it
          //maybe there is a need to create a custom exception for this kind of situation
          if (reason is Failure f && f.Cause is null)
          {
              reason = new Failure(new ArgumentNullException("cause"));
           }
         LogTermination(reason);
         foreach (var t in _timers)
         {
              t.Value.Cancel();
          }
          _timers.Clear();
          _timeoutFuture?.Cancel();
          _currentState = upcomingState;
                
          var stopEvent = new StopEvent<TState, TData>(reason, _currentState.StateName, _currentState.StateData);
           _terminateEvent(stopEvent);
        }
}

@ismaelhamed
Copy link
Member

LogTermination should handle the case when Cause is null and don't log. If that is not the desired behavior, LogTermination can always be overridden.

@eaba
Copy link
Contributor

eaba commented Dec 2, 2020

@ismaelhamed ?:

/// <summary>
/// By default, <see cref="Failure"/> is logged at error level and other
/// reason types are not logged. It is possible to override this behavior.
/// Should handle the case when Cause is null and don't log. If that is not the desired behavior, LogTermination can always be overridden
/// </summary>
/// <param name="reason">TBD</param>
protected virtual void LogTermination(Reason reason)
        {
            var failure = reason as Failure;
            if (failure != null)
            {
                if (failure.Cause is Exception)
                {
                    _log.Error(failure.Cause.AsInstanceOf<Exception>(), "terminating due to Failure");
                }
                else if(!(failure.Cause is null))
                {
                    _log.Error(failure.Cause.ToString());
                }
            }
        }

@eaba eaba mentioned this issue Dec 2, 2020
@Arkatufus
Copy link
Contributor

Arkatufus commented Dec 2, 2020

LogTermination should handle the case when Cause is null and don't log. If that is not the desired behavior, LogTermination can always be overridden.

I'd rather have the reverse, LogTermination will always log an error, regardless if Cause is null or not. If this is not the desired behavior, LogTermination can be overriden. It makes the method a lot more consistent with no coding gotchas.

@ismaelhamed
Copy link
Member

Agree, it makes more sense. Actually, looks like they just log an empty/null error in the JVM.

@Aaronontheweb Aaronontheweb added this to the 1.4.13 milestone Dec 3, 2020
This was referenced Dec 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants