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

Change a Scheduled Timer #21

Closed
alexzm1 opened this issue Sep 19, 2018 · 4 comments
Closed

Change a Scheduled Timer #21

alexzm1 opened this issue Sep 19, 2018 · 4 comments
Assignees

Comments

@alexzm1
Copy link

alexzm1 commented Sep 19, 2018

Is there any way to change the FireAfter TimeSpan of a Timer after being scheduled?

Here is a code snipped of what we're trying to do

`

public class TestWorkflow : Workflow {
//WorkflowDescription setup skiped
public TestWorkflow(){

	ScheduleActivity<TriggerTimerActivity>().OnCompletion(_=> Ignore);
	
	ScheduleTimer("TimerTest")
		.When(_=>false)
		.FireAfter(TimeSpan.FromMinutes(2)) //This might be changed by a Workflow Signal
		.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("start timer".EqualsIgnoreCase(@event.SignalName))
	{
		//Start the "TimerTest" using the @event.Input value as FireAfter TimeSpan value to setup
	}
	if ("cancel timer".EqualsIgnoreCase(@event.SignalName))
	{
		return CancelRequest.ForTimer(name: "TimerTest"); // Timer is cancelled after returning this
	}
	
	return Ignore;
}

}
`

@gurmitteotia
Copy link
Owner

gurmitteotia commented Sep 21, 2018

I have reread you question and I am sorry I am not able to fully match your question with the code. Timer.OnCancelled is not supported, and a new API Timer.OnCancel is added.
In version 1.1.14 I have also added a new Timer.FireAfter API which accepts the lambda and it will give you the flexibility to dynamically provide timeout.

Now regarding your question. If you want to reschedule a timer, which you have already scheduled then there is no nicer support in Amazon SWF for it. It would have been simpler if cancellation timer has raised the DecisionTaskScheduled event or it has allowed cancellation and scheduling in same decision. i.e.

 if (Timer("SomeTimer").IsActive)
     return CancelRequest.ForTimer("SomeTimer") + Jump.ToTimer("SomeTimer");

But none of above options are available and you have to use following workaround:

    public class OrderWorkflow : Workflow
    {
        public OrderWorkflow()
        {
            ScheduleTimer("GracePeriod").FireAfter(GracePeriodTimeout);
            ScheduleActivity<CancelOrder>().AfterTimer("GracePeriod")
                                               .When(a=> a.ParentTimer().IsCancelled()) ;

            ScheduleActivity<ShipOrder>().AfterTimer("GracePeriod");
            ScheduleTimer("GracePeriodReschedule").When(_ => false)
                                     .OnFired(_ => Jump.ToTimer("GracePeriod"));
        }

        private TimeSpan GracePeriodTimeout(ITimerItem item)
        {
            if (AllSignalEvents.Any(a => a.SignalName == "change_time"))
                return TimeSpan.FromMinutes(20); // new time or read it is from signal details

            return TimeSpan.FromMinutes(10); //Default timeout
        }
        [WorkflowEvent(EventName.Signal)]
        public WorkflowAction Signal(WorkflowSignaledEvent @event)
        {
            var timer = Timer("GracePeriod");
            if (@event.SignalName == "change_time")
                if (timer.IsActive) return CancelRequest.For(timer) + Jump.ToTimer("GracePeriodReschedule");

            return Ignore;
        }
    }

In future I'm planning to support dynamic timers, where you can schedule timers independent of workflow steps and it will make above workaround more sensible.

@gurmitteotia gurmitteotia self-assigned this Sep 23, 2018
@gurmitteotia
Copy link
Owner

gurmitteotia commented Sep 26, 2018

I think it will be useful to have Timer.Reset() and Timer.Reschedule API available. These API are quite generic and and could be useful in many scenarios. I can see that implementation of these APIs will help in setting up the foundation for ParallelForEach feature. So in future you will be able to either reschedule or reset the timer as below (For simplicity and to stay focused I have removed other details from example) :

public class OrderWorkflow : Workflow
    {
        public OrderWorkflow()
        {
            ScheduleTimer("GracePeriod").FireAfter(TimeSpan.FromMinutes(30));
           
            ScheduleActivity<ShipOrder>().AfterTimer("GracePeriod");
        }

       [WorkflowEvent(EventName.Signal)]
        public WorkflowAction Signal(WorkflowSignaledEvent @event)
        {
            var timer = Timer("GracePeriod");
            if (@event.SignalName == "change_time")
                if (timer.IsActive) return timer.Reschedule(TimeSpan.FromMinutes(10));

            return Ignore;
        }
    }

@gurmitteotia
Copy link
Owner

I have created a ticket with initial ideas. Any input will be useful.

@gurmitteotia
Copy link
Owner

This feature is implemented in version 1.2.15.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants