Skip to content

Commit 2a809a6

Browse files
committed
Fold newInput and preserveUnprocessedEvents into ContinueAsNewOptions
Address review feedback from cgillum: fold newInput and preserveUnprocessedEvents into ContinueAsNewOptions so the new overload takes a single ContinueAsNewOptions parameter. - Add NewInput and PreserveUnprocessedEvents properties to ContinueAsNewOptions - Change ContinueAsNew(ContinueAsNewOptions?, object?, bool) to ContinueAsNew(ContinueAsNewOptions) - Update TaskOrchestrationContextWrapper to match - Update unit and integration tests
1 parent 916e1e3 commit 2a809a6

5 files changed

Lines changed: 53 additions & 27 deletions

File tree

src/Abstractions/ContinueAsNewOptions.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,26 @@
44
namespace Microsoft.DurableTask;
55

66
/// <summary>
7-
/// Options for <see cref="TaskOrchestrationContext.ContinueAsNew(ContinueAsNewOptions, object?, bool)"/>.
7+
/// Options for <see cref="TaskOrchestrationContext.ContinueAsNew(ContinueAsNewOptions)"/>.
88
/// </summary>
99
public class ContinueAsNewOptions
1010
{
11+
/// <summary>
12+
/// Gets or sets the JSON-serializable input data to re-initialize the instance with.
13+
/// </summary>
14+
public object? NewInput { get; set; }
15+
16+
/// <summary>
17+
/// Gets or sets a value indicating whether to preserve unprocessed external events
18+
/// across the restart. Defaults to <c>true</c>.
19+
/// </summary>
20+
/// <remarks>
21+
/// When set to <c>true</c>, any unprocessed external events are re-added into the new execution
22+
/// history when the orchestration instance restarts. When <c>false</c>, any unprocessed
23+
/// external events will be discarded when the orchestration instance restarts.
24+
/// </remarks>
25+
public bool PreserveUnprocessedEvents { get; set; } = true;
26+
1127
/// <summary>
1228
/// Gets or sets the new version for the restarted orchestration instance.
1329
/// </summary>

src/Abstractions/TaskOrchestrationContext.cs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -416,34 +416,29 @@ public virtual Task CallSubOrchestratorAsync(
416416
public abstract void ContinueAsNew(object? newInput = null, bool preserveUnprocessedEvents = true);
417417

418418
/// <summary>
419-
/// Restarts the orchestration, optionally with a new version, clearing the history.
419+
/// Restarts the orchestration with the specified options, clearing the history.
420420
/// </summary>
421421
/// <remarks>
422422
/// <para>
423-
/// This overload accepts <see cref="ContinueAsNewOptions"/> to control the restart behavior.
423+
/// This overload accepts <see cref="ContinueAsNewOptions"/> to control the restart behavior,
424+
/// including the new input, whether to preserve unprocessed events, and an optional new version.
424425
/// When <see cref="ContinueAsNewOptions.NewVersion"/> is set, the framework uses the new version
425426
/// to route the restarted instance to the appropriate orchestrator implementation, enabling
426-
/// version-based dispatch. When no version is specified (i.e., <paramref name="options"/> is
427-
/// <c>null</c> or <c>NewVersion</c> is not set), this method behaves identically to
428-
/// <see cref="ContinueAsNew(object?, bool)"/>.
427+
/// version-based dispatch.
429428
/// </para><para>
430-
/// The default implementation ignores <paramref name="options"/> and delegates to
431-
/// <see cref="ContinueAsNew(object?, bool)"/>. Subclasses that support version-based
429+
/// The default implementation delegates to
430+
/// <see cref="ContinueAsNew(object?, bool)"/> using the input and preserve-events values
431+
/// from <paramref name="options"/>. Subclasses that support version-based
432432
/// dispatch should override this method.
433433
/// </para><para>
434434
/// Orchestrator implementations should complete immediately after calling this method.
435435
/// </para>
436436
/// </remarks>
437-
/// <param name="options">Options for the continue-as-new operation, including an optional new version.</param>
438-
/// <param name="newInput">The JSON-serializable input data to re-initialize the instance with.</param>
439-
/// <param name="preserveUnprocessedEvents">
440-
/// If set to <c>true</c>, re-adds any unprocessed external events into the new execution
441-
/// history when the orchestration instance restarts. If <c>false</c>, any unprocessed
442-
/// external events will be discarded when the orchestration instance restarts.
443-
/// </param>
444-
public virtual void ContinueAsNew(ContinueAsNewOptions? options, object? newInput, bool preserveUnprocessedEvents)
437+
/// <param name="options">Options for the continue-as-new operation.</param>
438+
public virtual void ContinueAsNew(ContinueAsNewOptions options)
445439
{
446-
this.ContinueAsNew(newInput, preserveUnprocessedEvents);
440+
Check.NotNull(options);
441+
this.ContinueAsNew(options.NewInput, options.PreserveUnprocessedEvents);
447442
}
448443

449444
/// <summary>

src/Worker/Core/Shims/TaskOrchestrationContextWrapper.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -337,22 +337,28 @@ public override void SetCustomStatus(object? customStatus)
337337
/// <inheritdoc/>
338338
public override void ContinueAsNew(object? newInput = null, bool preserveUnprocessedEvents = true)
339339
{
340-
this.ContinueAsNew(options: null, newInput, preserveUnprocessedEvents);
340+
this.ContinueAsNew(new ContinueAsNewOptions
341+
{
342+
NewInput = newInput,
343+
PreserveUnprocessedEvents = preserveUnprocessedEvents,
344+
});
341345
}
342346

343347
/// <inheritdoc/>
344-
public override void ContinueAsNew(ContinueAsNewOptions? options, object? newInput, bool preserveUnprocessedEvents)
348+
public override void ContinueAsNew(ContinueAsNewOptions options)
345349
{
346-
if (!string.IsNullOrWhiteSpace(options?.NewVersion))
350+
Check.NotNull(options);
351+
352+
if (!string.IsNullOrWhiteSpace(options.NewVersion))
347353
{
348-
this.innerContext.ContinueAsNew(options.NewVersion, newInput);
354+
this.innerContext.ContinueAsNew(options.NewVersion, options.NewInput);
349355
}
350356
else
351357
{
352-
this.innerContext.ContinueAsNew(newInput);
358+
this.innerContext.ContinueAsNew(options.NewInput);
353359
}
354360

355-
if (preserveUnprocessedEvents)
361+
if (options.PreserveUnprocessedEvents)
356362
{
357363
// Send all the buffered external events to ourself.
358364
OrchestrationInstance instance = new() { InstanceId = this.InstanceId };

test/Grpc.IntegrationTests/OrchestrationPatterns.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ public async Task ContinueAsNewWithNewVersion()
593593
{
594594
// First generation: migrate to "v2"
595595
await ctx.CreateTimer(TimeSpan.Zero, CancellationToken.None);
596-
ctx.ContinueAsNew(new ContinueAsNewOptions { NewVersion = "v2" }, input + 1, true);
596+
ctx.ContinueAsNew(new ContinueAsNewOptions { NewVersion = "v2", NewInput = input + 1 });
597597
return string.Empty;
598598
}
599599

test/Worker/Core.Tests/Shims/TaskOrchestrationContextWrapperTests.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,23 +71,32 @@ public void ContinueAsNew_WithVersion_CallsInnerContextWithVersion()
7171
TaskOrchestrationContextWrapper wrapper = new(innerContext, invocationContext, "input");
7272

7373
// Act
74-
wrapper.ContinueAsNew(new ContinueAsNewOptions { NewVersion = "v2" }, "new-input", preserveUnprocessedEvents: false);
74+
wrapper.ContinueAsNew(new ContinueAsNewOptions
75+
{
76+
NewVersion = "v2",
77+
NewInput = "new-input",
78+
PreserveUnprocessedEvents = false,
79+
});
7580

7681
// Assert
7782
innerContext.LastContinueAsNewInput.Should().Be("new-input");
7883
innerContext.LastContinueAsNewVersion.Should().Be("v2");
7984
}
8085

8186
[Fact]
82-
public void ContinueAsNew_WithNullOptions_CallsInnerContextWithoutVersion()
87+
public void ContinueAsNew_WithOptionsNoVersion_CallsInnerContextWithoutVersion()
8388
{
8489
// Arrange
8590
TrackingOrchestrationContext innerContext = new();
8691
OrchestrationInvocationContext invocationContext = new("Test", new(), NullLoggerFactory.Instance, null);
8792
TaskOrchestrationContextWrapper wrapper = new(innerContext, invocationContext, "input");
8893

8994
// Act
90-
wrapper.ContinueAsNew(options: null, newInput: "new-input", preserveUnprocessedEvents: false);
95+
wrapper.ContinueAsNew(new ContinueAsNewOptions
96+
{
97+
NewInput = "new-input",
98+
PreserveUnprocessedEvents = false,
99+
});
91100

92101
// Assert
93102
innerContext.LastContinueAsNewInput.Should().Be("new-input");

0 commit comments

Comments
 (0)