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

Workflow start delay #146

Merged
merged 4 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/Temporalio/Client/TemporalClient.Workflow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,10 @@ private async Task<WorkflowHandle<TWorkflow, TResult>> StartWorkflowInternalAsyn
{
req.SearchAttributes = input.Options.TypedSearchAttributes.ToProto();
}
if (input.Options.StartDelay is { } startDelay)
{
req.WorkflowStartDelay = Duration.FromTimeSpan(startDelay);
}
if (input.Headers != null)
{
req.Header = new();
Expand Down Expand Up @@ -489,6 +493,7 @@ private async Task<WorkflowHandle<TWorkflow, TResult>> StartWorkflowInternalAsyn
Memo = req.Memo,
SearchAttributes = req.SearchAttributes,
Header = req.Header,
WorkflowStartDelay = req.WorkflowStartDelay,
SignalName = input.Options.StartSignal,
};
if (input.Options.StartSignalArgs != null && input.Options.StartSignalArgs.Count > 0)
Expand Down
7 changes: 7 additions & 0 deletions src/Temporalio/Client/WorkflowOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ public WorkflowOptions(string id, string taskQueue)
/// </summary>
public SearchAttributeCollection? TypedSearchAttributes { get; set; }

/// <summary>
/// Gets or sets the amount of time to wait before starting the workflow.
/// </summary>
cretz marked this conversation as resolved.
Show resolved Hide resolved
/// <remarks>Start delay does not work with <see cref="CronSchedule" />.</remarks>
/// <remarks>WARNING: Start delay is experimental.</remarks>
public TimeSpan? StartDelay { get; set; }

/// <summary>
/// Gets or sets the start signal for the workflow. If this is non-null, a signal-with-start
/// is used instead of a traditional workflow start. This means the workflow will only be
Expand Down
39 changes: 39 additions & 0 deletions tests/Temporalio.Tests/Client/TemporalClientWorkflowTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,45 @@ await Client.StartWorkflowAsync(
});
}

[Fact]
public async Task StartWorkflowAsync_StartDelay_WaitsProperly()
cretz marked this conversation as resolved.
Show resolved Hide resolved
{
var arg = new KSWorkflowParams(new KSAction(Result: new(Value: "Some String")));
var handle = await Client.StartWorkflowAsync(
(IKitchenSinkWorkflowWithUnknownReturn wf) => wf.RunAsync(arg),
new(id: $"workflow-{Guid.NewGuid()}", taskQueue: Env.KitchenSinkWorkerTaskQueue)
{
StartDelay = TimeSpan.FromMinutes(45),
});
// Check that first event has start delay
await using var enumerator = handle.FetchHistoryEventsAsync().GetAsyncEnumerator();
Assert.True(await enumerator.MoveNextAsync());
var attrs = enumerator.Current.WorkflowExecutionStartedEventAttributes;
Assert.Equal(
TimeSpan.FromMinutes(45),
enumerator.Current.WorkflowExecutionStartedEventAttributes.FirstWorkflowTaskBackoff.ToTimeSpan());
}

[Fact]
public async Task StartWorkflowAsync_SignalWithStartDelay_WaitsProperly()
{
var arg = new KSWorkflowParams(new KSAction(Result: new(Value: "Some String")));
var handle = await Client.StartWorkflowAsync(
(IKitchenSinkWorkflowWithUnknownReturn wf) => wf.RunAsync(arg),
new(id: $"workflow-{Guid.NewGuid()}", taskQueue: Env.KitchenSinkWorkerTaskQueue)
{
StartDelay = TimeSpan.FromMinutes(45),
StartSignal = "some-signal",
});
// Check that first event has start delay
await using var enumerator = handle.FetchHistoryEventsAsync().GetAsyncEnumerator();
Assert.True(await enumerator.MoveNextAsync());
var attrs = enumerator.Current.WorkflowExecutionStartedEventAttributes;
Assert.Equal(
TimeSpan.FromMinutes(45),
enumerator.Current.WorkflowExecutionStartedEventAttributes.FirstWorkflowTaskBackoff.ToTimeSpan());
}

[Fact]
public async Task StartWorkflowAsync_StartSignal_Succeeds()
{
Expand Down
5 changes: 2 additions & 3 deletions tests/Temporalio.Tests/Testing/WorkflowEnvironmentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,8 @@ await worker.ExecuteAsync(async () =>
new(id: $"workflow-{Guid.NewGuid()}", taskQueue: worker.Options.TaskQueue!)));
// Check causes too
var actExc = Assert.IsType<ActivityFailureException>(exc.InnerException);
var toExc1 = Assert.IsType<TimeoutFailureException>(actExc.InnerException);
var toExc2 = Assert.IsType<TimeoutFailureException>(toExc1.InnerException);
Assert.Equal(TimeoutType.Heartbeat, toExc2.TimeoutType);
var toExc = Assert.IsType<TimeoutFailureException>(actExc.InnerException);
Assert.Equal(TimeoutType.Heartbeat, toExc.TimeoutType);
});
}

Expand Down
Loading