-
Notifications
You must be signed in to change notification settings - Fork 239
Dynamic workflows and activities #1946
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
Conversation
0dba4f7
to
ad35c64
Compare
internal/encode_args.go
Outdated
@@ -80,6 +80,11 @@ func decodeArgsToRawValues(dc converter.DataConverter, fnType reflect.Type, data | |||
} | |||
|
|||
// Unmarshal | |||
|
|||
// Dynamic workflows take in a single EncodedValues, encode all data into single EncodedValues |
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 thought it would be varargs of RawValue
, but encoded values makes sense too
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.
It is unfortunate we have both concepts, but EncodedValues
is more appropriate for dynamic workflows
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.
Hrmm. I think they're similar from a user POV for params (I personally prefer codec to apply outside workflow boundary), but we should allow any return value IMO.
In some SDKs we do not require a certain signature for a dynamic workflow. So if they want a dynamic workflow that accepts a string parameter, ok, it'll just fail with others. We offer the raw value option to all workflows including dynamic.
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.
Yeah the dynamic workflow should be allowed to return anything I agree, I was referring to the input type
internal/encode_args.go
Outdated
@@ -80,6 +80,11 @@ func decodeArgsToRawValues(dc converter.DataConverter, fnType reflect.Type, data | |||
} | |||
|
|||
// Unmarshal | |||
|
|||
// Dynamic workflows take in a single EncodedValues, encode all data into single EncodedValues | |||
if fnType.NumIn() == 2 && len(pointers) == 1 && fnType.In(1) == reflect.TypeOf((*converter.EncodedValues)(nil)).Elem() { |
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.
Hrmm, wonder if it's worth a more specific check whether it's a dynamic workflow/activity instead of assuming so based on signature? Maybe not worth it.
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.
Yeah I would consider a more specific check or just not sue this function for dynamic workflows/activities
internal/internal_worker.go
Outdated
@@ -929,7 +1011,10 @@ func (we *workflowExecutor) Execute(ctx Context, input *commonpb.Payloads) (*com | |||
// Execute and serialize result | |||
result, err := envInterceptor.inboundInterceptor.ExecuteWorkflow(ctx, &ExecuteWorkflowInput{Args: args}) | |||
var serializedResult *commonpb.Payloads | |||
if err == nil && result != nil { | |||
// Dynamic workflows always return EncodedValues, skip encoding because result should already be encoded |
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 they always return encoded values? There is no validation of this return type at registration time, and they don't really need to. For many, it may make more sense to return an any
or a RawValue
. Also, even if we do support encoded value as a return type, one might expect a single encoded value instead of plural (or at least have the option).
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.
Yeah it is a good question, In Java we require dynamic workflows to return an Object
so that is like any
in Go.
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.
Instead of any
, I think we should have no requirement on return type at all. Returning a RawValue
should be just fine for example. Even returning a string or no return value besides error I think should be fine. Although we did in the past, we don't have to require strict signatures nowadays for dynamic things if we don't want.
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'm in favor of matching the other non-Java SDKs and not requiring a return value. I don't think adding a return type requirement adds any guard rails for the users, so I wanna say matching behavior of the majority of the SDKs would be better.
internal/workflow.go
Outdated
// DynamicWorkflowOptions are options for a dynamic workflow. | ||
// | ||
// Exposed as: [go.temporal.io/sdk/workflow.DynamicWorkflowOptions] | ||
DynamicWorkflowOptions struct { |
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 wonder if we need a different name here. The concept of "workflow options" is traditionally used by workflow callers to set options about the workflow they are calling (e.g. StartWorkflowOptions
and ChildWorkflowOptions
).
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.
yeah I see what you're saying, maybe config
?
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.
Unsure, maybe DynamicWorkflowWorkerOptions
or something like that. @Quinn-With-Two-Ns - any ideas?
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.
RegisterDynamicWorkflowOptions
? similar to RegisterWorkflowOptions
I think this is a great case to try adding a sample and link to it in the PR, what do you think @yuandrew ? |
Good idea, added a sample and linked in PR description |
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.
Everything LGTM but still hung up on the naming of the type returned from LoadDynamicOptions
internal/workflow.go
Outdated
// Exposed as: [go.temporal.io/sdk/workflow.DynamicRegisterOptions] | ||
DynamicRegisterWorkflowOptions struct { | ||
// Allows dynamic options to be loaded for a workflow. | ||
LoadDynamicOptions func(details LoadDynamicOptionsDetails) (RegisterDynamicWorkflowOptions, error) |
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.
The more I think about this, the concept of DynamicRegisterWorkflowOptions
(even if exposed as DynamicRegisterOptions
) and RegisterDynamicWorkflowOptions
is just too confusingly named.
I think we should use the word "runtime" in here maybe, e.g.:
LoadDynamicOptions func(details LoadDynamicOptionsDetails) (RegisterDynamicWorkflowOptions, error) | |
LoadDynamicRuntimeOptions func(details LoadDynamicRuntimeOptionsDetails) (DynamicRuntimeWorkflowOptions, error) |
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.
Fine with me, whatever we do here we should also change the dynamic activity options name
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 is only specifically concerning runtime loading of workflow options by workflow type and has no activity anallog at this time
internal/internal_worker.go
Outdated
@@ -978,8 +1082,11 @@ func (ae *activityExecutor) ExecuteWithActualArgs(ctx context.Context, args []in | |||
result, resultErr := interceptor.ExecuteActivity(ctx, &ExecuteActivityInput{Args: args}) | |||
var serializedResult *commonpb.Payloads | |||
if result != nil { | |||
// Dynamic activities always return EncodedValues, skip encoding because result should already be encoded |
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.
Didn't we say we wanted dynamic workflows and activities to be able to return any value?
What was changed
Added support for dynamic workflows and activities.
Wrote a sample-go sample temporalio/samples-go#404, will merge once this feature goes in
Why?
Feature parity with other SDKs
Checklist
Closes Support dynamic activity and workflow implementations #543
Queries, signals, updates are tracked in a different issue: Support dynamic query and update handler #997
How was this tested:
Added new unit tests and integration tests
Any docs updates needed?