Skip to content

Commit

Permalink
I 22 Added support for Timer.Reset and Reschedule APIs (#33)
Browse files Browse the repository at this point in the history
* Added support for Timer.Reset and Timer.Reschedule APIs
* Allow workflow to be restarted with default properties
  • Loading branch information
gurmitteotia committed Nov 20, 2018
1 parent c978e6e commit d9f0cfe
Show file tree
Hide file tree
Showing 105 changed files with 1,861 additions and 1,294 deletions.
116 changes: 116 additions & 0 deletions Guflow.IntegrationTests/TimerResetTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// /Copyright (c) Gurmit Teotia. Please see the LICENSE file in the project root folder for license information.

using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Guflow.Decider;
using Guflow.Worker;
using NUnit.Framework;
using NUnit.Framework.Constraints;

namespace Guflow.IntegrationTests
{
[TestFixture]
public class TimerResetTests
{
private WorkflowHost _workflowHost;
private ActivityHost _activityHost;
private TestDomain _domain;
private static string _taskListName;

[SetUp]
public async Task Setup()
{
_domain = new TestDomain();
_taskListName = Guid.NewGuid().ToString();
_activityHost = await HostAsync(typeof(TestActivityWithInput));
}

[TearDown]
public void TearDown()
{
_workflowHost.StopExecution();
_activityHost.StopExecution();
}

[Test]
public async Task Reset_timer()
{
string result = "";
var @event = new ManualResetEvent(false);
var workflow = new ResetTimerWorkflow();
workflow.Closed += (s, e) => @event.Set();
workflow.Completed += (s, e) => { result = e.Result; };
_workflowHost = await HostAsync(workflow);

var workflowId = await _domain.StartWorkflow<ResetTimerWorkflow>("input", _taskListName);
Assert.True(workflow.WaitForWorkflowStart());
Thread.Sleep(6000); // TODO: get rid of this in future.
await _domain.SendSignal(workflowId, "ResetTimer", "");
@event.WaitOne();

Assert.That(workflow.TimerIsReset, Is.True);
}

private async Task<WorkflowHost> HostAsync(params Workflow[] workflows)
{
var hostedWorkflows = await _domain.Host(workflows);
hostedWorkflows.StartExecution(new TaskList(_taskListName));
return hostedWorkflows;
}

private async Task<ActivityHost> HostAsync(params Type[] activityTypes)
{
var hostedActivities = await _domain.Host(activityTypes);
hostedActivities.StartExecution(new TaskList(_taskListName));
return hostedActivities;
}

[WorkflowDescription(Names.Workflow.Test.Version, Name = Names.Workflow.Test.Name, DefaultChildPolicy = ChildPolicy.Abandon, DefaultExecutionStartToCloseTimeoutInSeconds = 900, DefaultTaskListName = "DefaultTaskList",
DefaultTaskPriority = 10, DefaultTaskStartToCloseTimeoutInSeconds = 900, Description = "Empty workflow")]
private class ResetTimerWorkflow : Workflow
{
private readonly AutoResetEvent _workflowStarted = new AutoResetEvent(false);
public ResetTimerWorkflow()
{
ScheduleTimer("Timer1").FireAfter(TimeSpan.FromSeconds(10))
.OnFired(e =>
{
if (Timer(e).AllEvents().OfType<TimerCancelledEvent>().Count() == 1)
TimerIsReset = true;
return Continue(e);
});
ScheduleActivity("TestActivity", "1.0").OnTaskList((t) => _taskListName).AfterTimer("Timer1");

ScheduleAction(i => CompleteWorkflow(i.ParentActivity().Result())).AfterActivity("TestActivity", "1.0");
}

[SignalEvent]
public WorkflowAction ResetTimer() => Timer("Timer1").IsActive ? Timer("Timer1").Reset() : Ignore;

[WorkflowEvent(EventName.WorkflowStarted)]
public WorkflowAction WorkflowStarted()
{
_workflowStarted.Set();
return StartWorkflow();
}
public bool TimerIsReset;

public bool WaitForWorkflowStart() => _workflowStarted.WaitOne(TimeSpan.FromSeconds(20));

}


[ActivityDescription(Names.Activity.Test.Version, Name = Names.Activity.Test.Name, DefaultTaskListName = "DefaultTaskList", DefaultTaskPriority = 10, Description = "some activity",
DefaultHeartbeatTimeoutInSeconds = 10, DefaultScheduleToStartTimeoutInSeconds = 10, DefaultStartToCloseTimeoutInSeconds = 10, DefaultScheduleToCloseTimeoutInSeconds = 20)]
private class TestActivityWithInput : Activity
{
[ActivityMethod]
public string Execute()
{
return "result";
}
}
}
}
9 changes: 5 additions & 4 deletions Guflow.Tests/Decider/Action/CancelWorkflowActionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ namespace Guflow.Tests.Decider
public class CancelWorkflowActionTests
{
private EventGraphBuilder _builder;
private const string ActivityName = "Download";
private const string ActivityVersion = "1.0";
private const string PositionalName = "First";

[SetUp]
public void Setup()
Expand Down Expand Up @@ -41,7 +44,8 @@ public void Serialize_complex_detail_object_to_json()
public void Can_be_returned_as_custom_action_in_workflow()
{
var workflow = new SingleActivityWorkflow("detail");
var completedActivityEventGraph = _builder.ActivityCompletedGraph(Identity.New(SingleActivityWorkflow.ActivityName, SingleActivityWorkflow.ActivityVersion, SingleActivityWorkflow.PositionalName), "id", "res");
var activityIdentity = Identity.New(ActivityName,ActivityVersion, PositionalName).ScheduleId();
var completedActivityEventGraph = _builder.ActivityCompletedGraph(activityIdentity, "id", "res");
var completedActivityEvent = new ActivityCompletedEvent(completedActivityEventGraph.First(), completedActivityEventGraph);

var decisions = completedActivityEvent.Interpret(workflow).Decisions();
Expand All @@ -51,9 +55,6 @@ public void Can_be_returned_as_custom_action_in_workflow()

private class SingleActivityWorkflow : Workflow
{
public const string ActivityName = "Download";
public const string ActivityVersion = "1.0";
public const string PositionalName = "First";
public SingleActivityWorkflow(string detail)
{
ScheduleActivity(ActivityName, ActivityVersion, PositionalName).OnCompletion(c => CancelWorkflow(detail));
Expand Down
9 changes: 5 additions & 4 deletions Guflow.Tests/Decider/Action/CompleteWorkflowActionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ namespace Guflow.Tests.Decider
public class CompleteWorkflowActionTests
{
private EventGraphBuilder _builder;
private const string ActivityName = "Download";
private const string ActivityVersion = "1.0";
private const string PositionalName = "First";

[SetUp]
public void Setup()
Expand Down Expand Up @@ -40,7 +43,8 @@ public void Serialize_complex_result_to_json()
public void Can_be_returned_as_custom_action_in_workflow()
{
var workflow = new WorkflowReturningCompleteWorkflowAction("result");
var completedActivityEventGraph = _builder.ActivityCompletedGraph(Identity.New(WorkflowReturningCompleteWorkflowAction.ActivityName, WorkflowReturningCompleteWorkflowAction.ActivityVersion, WorkflowReturningCompleteWorkflowAction.PositionalName), "id", "res");
var activityIdentity = Identity.New(ActivityName, ActivityVersion, PositionalName).ScheduleId();
var completedActivityEventGraph = _builder.ActivityCompletedGraph(activityIdentity, "id", "res");
var completedActivityEvent = new ActivityCompletedEvent(completedActivityEventGraph.First(), completedActivityEventGraph);

var decisions = completedActivityEvent.Interpret(workflow).Decisions();
Expand All @@ -50,9 +54,6 @@ public void Can_be_returned_as_custom_action_in_workflow()

private class WorkflowReturningCompleteWorkflowAction : Workflow
{
public const string ActivityName = "Download";
public const string ActivityVersion = "1.0";
public const string PositionalName = "First";
public WorkflowReturningCompleteWorkflowAction(string result)
{
ScheduleActivity(ActivityName, ActivityVersion, PositionalName).OnCompletion(c => CompleteWorkflow(result));
Expand Down
33 changes: 18 additions & 15 deletions Guflow.Tests/Decider/Action/ContinueWorkflowActionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ public void Returns_the_scheduling_decision_for_all_child_activities()
_eventsBuilder.AddNewEvents(CompletedActivityEventGraph(_activityName, _activityVersion, _positionalName));
var decisions = new WorkflowWithMultipleChilds().Decisions(_eventsBuilder.Result());

Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleActivityDecision(Identity.New("Transcode", "2.0")), new ScheduleActivityDecision(Identity.New("Sync", "2.1")) }));
Assert.That(decisions, Is.EquivalentTo(new[]
{
new ScheduleActivityDecision(Identity.New("Transcode", "2.0").ScheduleId()), new ScheduleActivityDecision(Identity.New("Sync", "2.1").ScheduleId())
}));
}

[Test]
Expand All @@ -63,7 +66,7 @@ public void Schedule_the_child_when_one_of_its_parents_branch_is_completed_and_o

var decisions = new WorkflowWithMultipleParents().Decisions(_eventsBuilder.Result());

Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleActivityDecision(Identity.New("Transcode", "2.0"))}));
Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleActivityDecision(Identity.New("Transcode", "2.0").ScheduleId()) }));

}
[Test]
Expand All @@ -84,7 +87,7 @@ public void Does_not_schedule_the_child_when_one_of_its_parent_activity_is_activ
{
_eventsBuilder.AddNewEvents(CompletedActivityEventGraph(_activityName, _activityVersion, _positionalName));
_eventsBuilder.AddNewEvents(_eventGraphBuilder
.ActivityScheduledGraph(Identity.New(_siblingActivityName, _siblingActivityVersion))
.ActivityScheduledGraph(Identity.New(_siblingActivityName, _siblingActivityVersion).ScheduleId())
.ToArray());

var workflow = new WorkflowWithMultipleParents();
Expand All @@ -104,7 +107,7 @@ public void Return_scheduling_decision_for_child_when_all_of_its_parents_are_com

var decisions = workflow.Decisions(_eventsBuilder.Result());

Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleActivityDecision(Identity.New("Transcode", "2.0")) }));
Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleActivityDecision(Identity.New("Transcode", "2.0").ScheduleId()) }));
}
[Test]
public void Return_scheduling_decision_for_child_when_one_of_its_parent_is_completed_and_other_one_is_failed_but_configured_to_continue()
Expand All @@ -115,7 +118,7 @@ public void Return_scheduling_decision_for_child_when_one_of_its_parent_is_compl

var decisions = workflow.Decisions(_eventsBuilder.Result());

Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleActivityDecision(Identity.New("Transcode", "2.0")) }));
Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleActivityDecision(Identity.New("Transcode", "2.0").ScheduleId()) }));
}

[Test]
Expand All @@ -127,7 +130,7 @@ public void Return_scheduling_decision_for_child_when_one_of_its_parent_is_compl

var decisions = workflow.Decisions(_eventsBuilder.Result());

Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleActivityDecision(Identity.New("Transcode", "2.0")) }));
Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleActivityDecision(Identity.New("Transcode", "2.0").ScheduleId()) }));
}

[Test]
Expand All @@ -140,7 +143,7 @@ public void Return_scheduling_decision_for_child_when_one_of_its_parent_is_compl

var decisions = workflow.Decisions(_eventsBuilder.Result());

Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleActivityDecision(Identity.New("Transcode", "2.0")) }));
Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleActivityDecision(Identity.New("Transcode", "2.0").ScheduleId()) }));
}

[Test]
Expand All @@ -153,7 +156,7 @@ public void Should_return_scheduling_decision_for_child_timer_when_parent_timer_
var decisions = workflow.Decisions(_eventsBuilder.Result());


Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleTimerDecision(Identity.Timer(childTimer), childTimeout) }));
Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleTimerDecision(Identity.Timer(childTimer).ScheduleId(), childTimeout) }));
}

[Test]
Expand All @@ -165,7 +168,7 @@ public void Should_return_scheduling_decision_for_child_activity_when_parent_tim

var decisions = workflow.Decisions(_eventsBuilder.Result());

Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleActivityDecision(Identity.New(_activityName, _activityVersion)) }));
Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleActivityDecision(Identity.New(_activityName, _activityVersion).ScheduleId()) }));
}

[Test]
Expand All @@ -176,7 +179,7 @@ public void Can_return_the_scheduling_decision_for_child_timer_when_parent_activ
_eventsBuilder.AddNewEvents(CompletedActivityEventGraph(_activityName, _activityVersion, _positionalName));
var decisions = workflow.Decisions(_eventsBuilder.Result());

Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleTimerDecision(Identity.Timer(timerName),new TimeSpan())}));
Assert.That(decisions, Is.EquivalentTo(new[] { new ScheduleTimerDecision(Identity.Timer(timerName).ScheduleId(),new TimeSpan())}));
}

[Test]
Expand Down Expand Up @@ -204,26 +207,26 @@ public void Can_return_scheduling_decision_for_workflow_action_when_all_of_its_p

private HistoryEvent [] FailedActivityEventGraph(string activityName, string activityVersion, string positionalName ="")
{
return _eventGraphBuilder.ActivityFailedGraph(Identity.New(activityName, activityVersion, positionalName), "id", "res", "detail").ToArray();
return _eventGraphBuilder.ActivityFailedGraph(Identity.New(activityName, activityVersion, positionalName).ScheduleId(), "id", "res", "detail").ToArray();
}
private HistoryEvent[] CompletedActivityEventGraph(string activityName, string activityVersion, string positionalName ="")
{
return _eventGraphBuilder.ActivityCompletedGraph(Identity.New(activityName, activityVersion, positionalName), "id", "res").ToArray();
return _eventGraphBuilder.ActivityCompletedGraph(Identity.New(activityName, activityVersion, positionalName).ScheduleId(), "id", "res").ToArray();
}

private HistoryEvent[] CancelledActivityEventGraph(string activityName, string activityVersion, string positionalName = "")
{
return _eventGraphBuilder.ActivityCancelledGraph(Identity.New(activityName, activityVersion, positionalName), "id", "res").ToArray();
return _eventGraphBuilder.ActivityCancelledGraph(Identity.New(activityName, activityVersion, positionalName).ScheduleId(), "id", "res").ToArray();
}

private HistoryEvent[] TimedoutActivityEventGraph(string activityName, string activityVersion, string positionalName = "")
{
return _eventGraphBuilder.ActivityTimedoutGraph(Identity.New(activityName, activityVersion, positionalName), "id", "res", "det").ToArray();
return _eventGraphBuilder.ActivityTimedoutGraph(Identity.New(activityName, activityVersion, positionalName).ScheduleId(), "id", "res", "det").ToArray();
}

private HistoryEvent[] TimerFiredEventGraph(string timerName)
{
return _eventGraphBuilder.TimerFiredGraph(Identity.Timer(timerName), TimeSpan.FromSeconds(2)).ToArray();
return _eventGraphBuilder.TimerFiredGraph(Identity.Timer(timerName).ScheduleId(), TimeSpan.FromSeconds(2)).ToArray();
}

private class WorkflowWithMultipleChilds : Workflow
Expand Down
9 changes: 5 additions & 4 deletions Guflow.Tests/Decider/Action/FailWorkflowActionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ namespace Guflow.Tests.Decider
public class FailWorkflowActionTests
{
private EventGraphBuilder _builder;
private const string ActivityName = "Download";
private const string ActivityVersion = "1.0";
private const string PositionalName = "First";

[SetUp]
public void Setup()
Expand Down Expand Up @@ -41,7 +44,8 @@ public void Serialize_complex_detail_object_to_json()
public void Can_be_returned_as_custom_action_in_workflow()
{
var workflow = new SingleActivityWorkflow("reason","detail");
var completedActivityEventGraph = _builder.ActivityCompletedGraph(Identity.New(SingleActivityWorkflow.ActivityName, SingleActivityWorkflow.ActivityVersion, SingleActivityWorkflow.PositionalName), "id", "res");
var activityIdentity = Identity.New(ActivityName, ActivityVersion, PositionalName).ScheduleId();
var completedActivityEventGraph = _builder.ActivityCompletedGraph(activityIdentity, "id", "res");
var completedActivityEvent = new ActivityCompletedEvent(completedActivityEventGraph.First(), completedActivityEventGraph);

var decisions = completedActivityEvent.Interpret(workflow).Decisions();
Expand All @@ -51,9 +55,6 @@ public void Can_be_returned_as_custom_action_in_workflow()

private class SingleActivityWorkflow : Workflow
{
public const string ActivityName = "Download";
public const string ActivityVersion = "1.0";
public const string PositionalName = "First";
public SingleActivityWorkflow(string reason, string detail)
{
ScheduleActivity(ActivityName, ActivityVersion, PositionalName).OnCompletion(c => FailWorkflow(reason, detail));
Expand Down
3 changes: 2 additions & 1 deletion Guflow.Tests/Decider/Action/IgnoreWorkflowActionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ public void Can_be_returned_as_custom_action_from_workflow()
}
private ActivityCompletedEvent CreateCompletedActivityEvent(string activityName, string activityVersion)
{
var allHistoryEvents = _builder.ActivityCompletedGraph(Identity.New(activityName, activityVersion, string.Empty), "id", "res");
var activityIdentity = Identity.New(activityName, activityVersion, string.Empty).ScheduleId();
var allHistoryEvents = _builder.ActivityCompletedGraph(activityIdentity, "id", "res");
return new ActivityCompletedEvent(allHistoryEvents.First(), allHistoryEvents);
}
private class WorkflowReturningStartWorkflowAction : Workflow
Expand Down
Loading

0 comments on commit d9f0cfe

Please sign in to comment.