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

Timer.Cancel() #19

Closed
mirel-maestral opened this issue Sep 17, 2018 · 15 comments
Closed

Timer.Cancel() #19

mirel-maestral opened this issue Sep 17, 2018 · 15 comments
Assignees
Projects

Comments

@mirel-maestral
Copy link

Is it possible to cancel a Timer from the code?

@mirel-maestral mirel-maestral changed the title Tiemer.Cancel() Timer.Cancel() Sep 17, 2018
@alexzm1
Copy link

alexzm1 commented Sep 17, 2018

I believe the way to cancel a Timer from a Workflow inheriting class is sending the WorkflowAction obtained when calling
CancelRequest.ForTimer(name: "TimerName")

The only Issue I have seen doing this is that, the configured Function in method OnCancelled of SchedullerTimer is not being executed after Timer Cancellation via CancelRequest.ForTimer method.

I.E.

SchedulerTimer(name: "TimerName").OnCancelled(_=> //Do Something which will return a WorkflowAction);

@alexzm1
Copy link

alexzm1 commented Sep 17, 2018

Here is a code snipped that could help to understand the problem

`
public class TestWorkflow : Workflow {

//WorkflowDescription setup skiped  

public TestWorkflow(){

	ScheduleActivity<TriggerTimerActivity>();
	
	ScheduleTimer("TimerTest")
		.AfterActivity<TriggerTimerActivity>()
		.FireAfter(TimeSpan.FromMinutes(2))
		.OnFired(_ =>
			{
				return FailWorkflow("Failed Cancel Timer", "Failed to cancel TimerTest"); //Executed after timer's TimeSpan (2 minutes in this case)
			})
		.OnCancelled(_ =>
			{
				return CompleteWorkflow("Workflow Execution Completed"); //Not Executed After timer cancellation
			}
		);

}

[WorkflowEvent(EventName.Signal)]
public WorkflowAction OnSignal(WorkflowSignaledEvent @event)
{
	if ("cancel timer".EqualsIgnoreCase(@event.SignalName))
	{
		return CancelRequest.ForTimer(name: "TimerTest"); // Timer is cancelled after returning this
	}
}

}
`

@gurmitteotia
Copy link
Owner

OnCancelled should execute when timer is cancelled. I will have a look.
Meanwhile can you check following things please:

  • Make sure in history events that timer is being cancelled. You can login to AWS console to check history events of a particular workflow
  • Check if workflow host is reporting any error. You can log any error as below:
workflow.OnError(e=>{
  //Or log it
 Console.WriteLine(e.Exception);
return ErrorAction.Continue;
});

You can read more about exception handling here

  • Put a guard before cancelling the timer. If you try to cancel a timer which is not active than the event will be raised to indicate that cancellation has failed. It will cause the workflow to fail. However you can handle to provide other workflow action:
public TestWorkflow(){


	ScheduleTimer("TimerTest")
		.AfterActivity<TriggerTimerActivity>()
		.FireAfter(TimeSpan.FromMinutes(2))
		.OnFired(_ =>
			{
				return FailWorkflow("Failed Cancel Timer", "Failed to cancel TimerTest"); //Executed after timer's TimeSpan (2 minutes in this case)
			})
		.OnCancelled(_ =>
			{
				return CompleteWorkflow("Workflow Execution Completed"); //Not Executed After timer cancellation
			}
		).OnCancellationFailed(_=>Provide your custom action);

}

[WorkflowEvent(EventName.Signal)]
public WorkflowAction OnSignal(WorkflowSignaledEvent @event)
{
    
	if ("cancel timer".EqualsIgnoreCase(@event.SignalName))
	{
              if (Timer("TimerTest").IsActive)
                    return CancelRequest.ForTimer("TimerTest");
	}
        return Ignore;
}

@gurmitteotia
Copy link
Owner

This is the issue with Amazon SWF. I can see in history event that is timer is cancelled but decision tasks are not scheduled. OnCancelled event will be raised only when decision tasks are scheduled. I will raise this on Amazon's SWF forum. I have attached the image of history events I saw:
aws_events

@alexzm1
Copy link

alexzm1 commented Sep 17, 2018

Hi Gurmit!

Just checked and the SWF console is showing the Timer as cancelled in the Events History tab, also I'm not getting any error logged on any of the Workflow Error handlers I've setup (OnError, OnPollingError, OnResponseError or OnFault).

I also setup OnCancellationFailed in my timer but it seems that not even that function is being invoked when I cancel the Timer.

@gurmitteotia
Copy link
Owner

I'm raising it on Amazon SWF forum but I doubt we will get a quick answer from there. I think you should use following workaround for now:

public TestWorkflow(){


	ScheduleTimer("TimerTest")
		.AfterActivity<TriggerTimerActivity>()
		.FireAfter(TimeSpan.FromMinutes(2))
		.OnFired(_ =>
			{
				return FailWorkflow("Failed Cancel Timer", "Failed to cancel TimerTest"); //Executed after timer's TimeSpan (2 minutes in this case)
			})
		).OnCancellationFailed(_=>Provide your custom action);

}

[WorkflowEvent(EventName.Signal)]
public WorkflowAction OnSignal(WorkflowSignaledEvent @event)
{
    
	if ("cancel timer".EqualsIgnoreCase(@event.SignalName))
	{
              if (Timer("TimerTest").IsActive)
                    return CompleteWorkflow("Workflow Execution Completed");
	}
        return Ignore;
}

@gurmitteotia
Copy link
Owner

I have raised it on Amazon SWF https://forums.aws.amazon.com/thread.jspa?threadID=290071&tstart=0

@alexzm1
Copy link

alexzm1 commented Sep 17, 2018

Got it! n thanks for following up on this.

Also let´s say we have a few more Activities that we were supposed to call after Timer Cancellation, rather than just closing the Workflow like in the previous example, what would you recommend us to do?

`
public class TestWorkflow : Workflow {

//WorkflowDescription setup skiped  

public TestWorkflow(){

	ScheduleActivity<TriggerTimerActivity>();
	
	ScheduleTimer("TimerTest")
		.AfterActivity<TriggerTimerActivity>()
		.FireAfter(TimeSpan.FromMinutes(2))
		.OnFired(_ =>
			{
				return FailWorkflow("Failed Cancel Timer", "Failed to cancel TimerTest"); //Executed after timer's TimeSpan (2 minutes in this case)
			})
		.OnCancelled(_ =>
			{
				return Jump.ToActivity<AfterTimerActivity>(); //Not Executed After timer cancellation
			}
		);
	
	ScheduleActivity<AfterTimerActivity>().AfterTimer("TimerTest").OnCompletion(_=>{
		return CompleteWorkflow("Workflow Execution Completed");
	});
	
}

[WorkflowEvent(EventName.Signal)]
public WorkflowAction OnSignal(WorkflowSignaledEvent @event)
{
	if ("cancel timer".EqualsIgnoreCase(@event.SignalName))
	{
		if (Timer("TimerTest").IsActive)
			return CancelRequest.ForTimer("TimerTest");
	}
    return Ignore;
}

}
`

@gurmitteotia
Copy link
Owner

gurmitteotia commented Sep 17, 2018

In following example OrderCancelled activity is scheduled when timer is cancelled while ShipOrder activity is scheduled when timer is successfully fired.

[WorkflowDescription("1.0")]
public class OrderWorkflow : Workflow
{

 public OrderWorkflow()
 {
 
	ScheduleTimer("GracePeriod").FireAfter(TimeSpan.FromMinutes(20))
                                        .OnCancelled(_=>Ignore); //I will remove it in next version
                                        .OnFired(_=>Jump.ToActivity<ShipOrder>());
	ScheduleActivity<OrderCancelled>().AfterTimer("GracePeriod");
	ScheduleActivity<ShipOrder>().AfterTimer("GracePeriod");
  }
  
  [WorkflowEvent(EventName.Signal)]
  public WorkflowAction OnSignal(WorkflowSignaledEvent @event)
 {
	if ("cancel timer".EqualsIgnoreCase(@event.SignalName))
	{
	    //You can combine multiple workflow actions together
           if (Timer("GracePeriod").IsActive)
			return CancelRequest.ForTimer("GracePeriod") + Jump.ToActivity<OrderCancelled>();
	}
    return Ignore;
 }
}

Hope that helps!

@alexzm1
Copy link

alexzm1 commented Sep 17, 2018

Wow! that's a big surprise, I wasn't expecting to be able to return concatenated WorkflowActions.

Again thanks for your help!

@gurmitteotia
Copy link
Owner

Yes, it does you can read more about it here. Understanding of Deflow algorithm and workflow execution will give you a pretty good understanding on workflow is executed.

@gurmitteotia
Copy link
Owner

I will update the Guflow library to align with Amazon SWF. You can find my response here. In my opinion it would be better to raise ScheduleDecisionTask event for TimerCancelled event. I will raise it a feature request if I come to know about the right place to raise it. Please use the suggested example above. I have updated it to make to more meaningful.

@alexzm1
Copy link

alexzm1 commented Sep 20, 2018

Will do! Thanks

@gurmitteotia
Copy link
Owner

I have released the new version 1.1.14. Please look at release notes for more details.

In new version you will write the above workflow as below:

[WorkflowDescription("1.0")]
public class OrderWorkflow : Workflow
{
 public OrderWorkflow()
 {
 
	ScheduleTimer("GracePeriod").FireAfter(TimeSpan.FromMinutes(20))
                                        .OnCancel(_=>Jump.ToActivity<OrderCancelled>())
                                        .OnFired(_=>Jump.ToActivity<ShipOrder>());
	ScheduleActivity<OrderCancelled>().AfterTimer("GracePeriod");
	ScheduleActivity<ShipOrder>().AfterTimer("GracePeriod");
  }
  
  [WorkflowEvent(EventName.Signal)]
  public WorkflowAction OnSignal(WorkflowSignaledEvent @event)
 {
	if ("cancel timer".EqualsIgnoreCase(@event.SignalName))
	{
           if (Timer("GracePeriod").IsActive)
			return CancelRequest.ForTimer("GracePeriod");
	}
    return Ignore;
 }
}

@gurmitteotia gurmitteotia self-assigned this Sep 21, 2018
@gurmitteotia gurmitteotia added this to To Do in Guflow via automation Sep 21, 2018
@gurmitteotia
Copy link
Owner

I'm closing it now as this issue is resolved.

Guflow automation moved this from To Do to Done Sep 21, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Guflow
  
Done
Development

No branches or pull requests

3 participants