Skip to content

support continue as new pattern#22

Merged
kaibocai merged 2 commits intomainfrom
kaibocai/continue-as-new
Apr 5, 2022
Merged

support continue as new pattern#22
kaibocai merged 2 commits intomainfrom
kaibocai/continue-as-new

Conversation

@kaibocai
Copy link
Copy Markdown
Member

@kaibocai kaibocai commented Apr 1, 2022

This pr includes:

  • add logics for supporting continue as new pattern
  • add on end2end test case

refer to #6

this.historyEventPlayer = new OrchestrationHistoryIterator(pastEvents, newEvents);
}

// private void initialize(){
Copy link
Copy Markdown
Member Author

@kaibocai kaibocai Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is never invoked, but still pass the test. I am wondering where I made the mistake. @cgillum @davidmrdavid please help.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What were you expected this code would be needed for? I'm not sure if this is actually needed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Python SDK has something like this here -https://github.com/Azure/azure-functions-durable-python/blob/2f679e9e6507e7c41195fc752c26e215c532e014/azure/durable_functions/models/TaskOrchestrationExecutor.py#L109

In essence, in Python the initialize method helps "clear" the orchestrator's state when a continue_as_new event is processed by the TaskOrchestrationExecutor.

However, in a later comment you clarify that the Continue_as_new is no longer an event type, which is news to me :) . So if this is already being handled in "the backend", then this is certainly not needed

// break;
// case CONTINUEASNEW:
// break;
case CONTINUEASNEW:
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when debugging the test, never see a event with this type coming. but the test still pass. @cgillum @davidmrdavid please help.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is expected. Only older versions of the Durable Task Framework actually use this event. Newer versions implement this handling directly in the host. We can remove it from the switch statement.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, this is new to me. So is it fair to conclude that, moving forward, OOProc PLs don't need to handle ContinueAsNew history events at all?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think it's fair to ignore this moving forward.

@kaibocai kaibocai requested review from cgillum and davidmrdavid April 1, 2022 22:01
Copy link
Copy Markdown
Member

@cgillum cgillum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad to see you got this working so quickly! Some feedback:


void continueAsNew(Object input, boolean preserveUnprocessedEvents );

void sendEvent(OrchestratorService.OrchestrationInstance instance, String eventName, Object eventData);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of exposing the gRPC types in the public API (OrchestratorService.*), let's just have the user pass in the orchestration instance ID as a String. Something like this:

void sendEvent(String instanceId, String eventName, Object eventData);

The internal implementation of sendEvent can then construct the OrchestrationInstance object.

Also, consider adding a default overload that passes null for eventData.

// break;
// case CONTINUEASNEW:
// break;
case CONTINUEASNEW:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is expected. Only older versions of the Durable Task Framework actually use this event. Newer versions implement this handling directly in the host. We can remove it from the switch statement.

// Send all the buffered external events to ourself.
OrchestrationInstance.Builder OrchestrationInstanceBuilder = OrchestrationInstance.newBuilder().setInstanceId(this.instanceId);
for (EventRaisedEvent unprocessedEvent : unprocessedEvents) {
this.sendEvent(OrchestrationInstanceBuilder.build(), unprocessedEvent.getName(), unprocessedEvent.getInput());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per my other feedback let's replace OrchestrationInstanceBuilder.build() with this.instanceId.

this.historyEventPlayer = new OrchestrationHistoryIterator(pastEvents, newEvents);
}

// private void initialize(){
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What were you expected this code would be needed for? I'm not sure if this is actually needed.

}

@Override
public void continueAsNew(Object input, boolean preserveUnprocessedEvents ){
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: fix whitespace here

Suggested change
public void continueAsNew(Object input, boolean preserveUnprocessedEvents ){
public void continueAsNew(Object input, boolean preserveUnprocessedEvents) {

private boolean isComplete;
private boolean hasContinueAsNew;


Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: let's remove this extra whitespace.

static void throwIfArgumentNullOrWhiteSpace(String argValue, String argName) {
throwIfArgumentNull(argValue, argName);
if (argValue.trim().length() == 0){
throw new IllegalArgumentException("Argument '" + argName + "' was WhiteSpace.");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rephrase this slightly:

Suggested change
throw new IllegalArgumentException("Argument '" + argName + "' was WhiteSpace.");
throw new IllegalArgumentException("The argument '" + argName + "' was empty or contained only whitespace.");

.build());
this.hasContinueAsNew = true;

if (preserveUnprocessedEvents){
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add another integration test that covers this case (unprocessed events). Basically, you should write an orchestration that listens for a single external event and then immediately does ctx.continueAsNew(n + 1). The client should then start an orchestration and, without waiting, immediately raise N external events to the orchestration. For example, 10 events. The client should then wait for the orchestration to complete and verify that the input (and/or output) on the OrchestrationMetadata object is 10, meaning that all 10 external events were processed.

Copy link
Copy Markdown
Member

@davidmrdavid davidmrdavid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Chris' suggestions. Also left some thoughts and questions, mostly for Chris as well :)

//TODO: add logic for newVersion
CompleteOrchestrationAction.Builder completeOrchestrationActionBuilder = CompleteOrchestrationAction.newBuilder()
.setOrchestrationStatus(OrchestrationStatus.ORCHESTRATION_STATUS_CONTINUED_AS_NEW)
.setNewVersion(StringValue.of(""));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I keep on seeing this version stuff in the actions, which the old out-of-process model did not need. Is this a new requirement, @cgillum?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Durable Task Framework has a concept of versions of activities and orchestrations. However, we never exposed it to Durable Functions because I couldn't reason about how to leverage it effectively. I went ahead and carried it forward for the OOProc protocols since I want those to work with DTFx but even in the new SDKs we don't actually use them anywhere. At some point we'll want to spend time thinking about how to implement versioning, but we're not there quite yet.

// break;
// case CONTINUEASNEW:
// break;
case CONTINUEASNEW:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, this is new to me. So is it fair to conclude that, moving forward, OOProc PLs don't need to handle ContinueAsNew history events at all?

@kaibocai kaibocai force-pushed the kaibocai/continue-as-new branch from 8bda6dd to 9216d6e Compare April 4, 2022 21:22
@cgillum
Copy link
Copy Markdown
Member

cgillum commented Apr 5, 2022

@kaibocai please sync the latest changes from this PR so that you have my updates locally on your machine. It would be sad if you accidentally force-push and delete my changes. :)

@kaibocai kaibocai marked this pull request as ready for review April 5, 2022 01:33
Support for "carryover" events (#25)
@kaibocai kaibocai force-pushed the kaibocai/continue-as-new branch from 23bce59 to 1c2da39 Compare April 5, 2022 02:02
@kaibocai kaibocai linked an issue Apr 5, 2022 that may be closed by this pull request
Copy link
Copy Markdown
Member

@cgillum cgillum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@kaibocai kaibocai merged commit c1f55c2 into main Apr 5, 2022
@kaibocai kaibocai deleted the kaibocai/continue-as-new branch April 5, 2022 17:01
@kaibocai kaibocai requested a review from amamounelsayed April 5, 2022 21:59
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

Successfully merging this pull request may close these issues.

Continue-as-new support

3 participants