-
Notifications
You must be signed in to change notification settings - Fork 132
Activity reset #1730
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
Activity reset #1730
Conversation
Blocked on the merge of: and server release that populates |
de50973
to
3ee7227
Compare
e0d0403
to
ab76e93
Compare
await handle.client.workflowService.unpauseActivity(req); | ||
} else { | ||
const resetReq = { ...req, resetHeartbeat: true }; | ||
await handle.client.workflowService.resetActivity(resetReq); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am looking into doing this in other langs too, can you confirm the current dev server supports this and/or do we need to upgrade to an RC one for tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As in supports the resetActivity
call? Yes should be fine. Latest CLI version is 1.4.1, which has temporal server version 1.28.0. ResetActivity
was included in 1.27.1 with some improvements in 1.28.0
Edit: will need to set frontend.activityAPIsEnabled
to true to enable this API
} | ||
} catch (err) { | ||
this.handleError(err); | ||
} | ||
if (cancelRequested) { | ||
throw new ActivityCancelledError('cancelled'); | ||
} | ||
if (reset) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we be worried about this cascade of if
statements? Can multiple of these conditions be true at the same time? If so, are we 100% sure about the order?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it's possible for multiple of these conditions can be true at the same time - user issues an activity cancel and a reset command between heartbeats (not sure if server has some logic that guards against this).
In any case, the ordering of these statements follows that of core:
https://github.com/temporalio/sdk-core/blob/d34c1d6d393462a816baf2469c256a21ffbaf196/core/src/worker/activities/activity_heartbeat_manager.rs#L148-L159
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, though more than one may be true, the way this is written where each branch throws, that's kind of irrelevant. I would make them elses for that reason I think.
// • the activity vanished (already completed) | ||
return activityInfo ? !activityInfo.paused : true; | ||
if (state === 'pause') { | ||
return activityInfo ? activityInfo.paused ?? false : true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not new code, but pretty hard on reader.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
// If cancel due to activity pause, emit an application failure for the pause. | ||
if (this.context.cancellationDetails?.paused) { | ||
// If cancel due to activity pause or reset, emit an application failure. | ||
if (this.context.cancellationDetails?.reset) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we confident on if clause ordering? reset vs pause?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Between reset and pause yes. Added a conditional for explicit cancellations, ordered before the reset
branch (to keep the cancellation -> reset -> pause ordering, though this is just for logging)
failed: { | ||
failure: await encodeErrorToFailure( | ||
this.dataConverter, | ||
new ApplicationFailure('Activity reset', 'ActivityReset') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Retryable or not? Prefer making this explicit, for the benefit of readers.
- Is there any official semantic on this error? Does the server expect specific type?
- Should we avoid attaching stack trace on that specific error?
I'm a bit concerned here that ApplicationFailure
are meant for user usage, so exposing activity reset as that error type might be "misinterpreted" as something they need to investigate, so they would look at the stack trace and try to figure it out. "Activity Reset" is a pretty generic name, an error message that users could have written themselves...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I've make non-retryable explicitly false.
- The server does not expect a specific error type (this error returned is agnostic to server)
- I don't really see a reason why
I'm less concerned about using ApplicationFailure
for this, partly because it's a user-triggered error, and because it's what we chose to do for Python and TS for activity pause (though other SDKs diverge - Java introduced ActivityPausedException
as a subtype of ActivityCompletionException
, Go cancels the context with a ErrActivityPaused
cause).
The alternative is we don't wrap and we emit a CancelledFailure
with message RESET
, see:
https://github.com/temporalio/sdk-typescript/blob/9089bc682b4334287e52cd0bdb4547836f63e335/packages/worker/src/activity.ts#L77-84
and
https://github.com/temporalio/sdk-typescript/blob/9089bc682b4334287e52cd0bdb4547836f63e335/packages/worker/src/worker.ts#L1072-1092
(the else
conditional)
Whatever choice we make, we should also apply to the pause
case, and potentially to Python as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Sushisource wdyt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO what Java (wrap with more specific types) is probably the most sensible. But I agree we'd need to apply it to Python and pause as well.
You should get @dandavison 's take and coordinate Python change with him
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tconley1428 is working on activity reset right now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then him, hehe 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After some discussion - we'll leave this as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had a very quick look at it, pointing out anything that popped to my mind without any real analysis, so be careful.
Leaving more complete review to @Sushisource.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense to me, approving, but I have couple minor things to address, and possibly an extra test to add.
// • the activity vanished (already completed) | ||
return activityInfo ? !activityInfo.paused : true; | ||
if (state === 'pause') { | ||
return activityInfo ? activityInfo.paused ?? false : true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
} | ||
} catch (err) { | ||
this.handleError(err); | ||
} | ||
if (cancelRequested) { | ||
throw new ActivityCancelledError('cancelled'); | ||
} | ||
if (reset) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, though more than one may be true, the way this is written where each branch throws, that's kind of irrelevant. I would make them elses for that reason I think.
t.deepEqual(result, { | ||
cancelRequested: false, | ||
notFound: false, | ||
paused: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have any tests where multiple things are true at once? EX: Paused and reset?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added
f028958
to
16ef9e5
Compare
16ef9e5
to
051ea89
Compare
What was changed
Added support to reset an activity. Cancellations due to reset are received through the heartbeat mechanism of the activity.
Why?
Part of activity operator work.
Closes [typescript] SDK support for activity reset #1693
How was this tested:
Integration test
Any docs updates needed?
Likely