-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Allow internal state to be globally configured independently of inputs/outputs #6982
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
base: patch/3.5.2
Are you sure you want to change the base?
Conversation
|
@bobhauser The diff is so big that I can't really get a good look at the actual changes. Is there any chance you can push only the relevant change without the reformatting? |
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.
Pull Request Overview
This PR fixes an issue where internal state persistence configuration was incorrectly inheriting from the workflow's default persistence mode for inputs/outputs, rather than having its own independent configuration hierarchy. The fix ensures that when the workflow default persistence mode is set to "Exclude", internal state can still be configured to persist globally using its own internalState configuration key.
Key Changes:
- Refactored persistence mode resolution to handle internal state separately from inputs/outputs
- Replaced the specialized
EvaluateInternalStateModeAsyncmethod with a generalizedGetPersistenceModeAsyncmethod - Introduced new constants for configuration keys to improve maintainability
| // Resolve internalStateMode for internal state. Resolution hierarchy: activity internal state -> activity default -> workflow internal state -> workflow default -> system default from options. | ||
| var workflowInternalStateDefaultMode = await GetPersistenceModeAsync(rootContext.ExpressionExecutionContext, workflow.CustomProperties, InternalStatePersistenceKey, () => workflowDefaultMode, cancellationToken); | ||
| var activityDefaultMode = await GetPersistenceModeAsync(context.ExpressionExecutionContext, context.Activity.CustomProperties, DefaultPersistenceKey, () => workflowInternalStateDefaultMode, cancellationToken); | ||
| var internalStateMode = await GetPersistenceModeAsync(context.ExpressionExecutionContext, context.Activity.CustomProperties, InternalStatePersistenceKey, () => activityDefaultMode, cancellationToken); |
Copilot
AI
Nov 12, 2025
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 resolution hierarchy comment on line 103 states the order as 'activity internal state -> activity default -> workflow internal state -> workflow default -> system default', but the implementation on lines 104-106 creates a different chain. Line 105 retrieves the activity's 'default' key with workflowInternalStateDefaultMode as fallback, meaning if the activity has a 'default' configured, it will override the workflow's 'internalState' setting. The actual hierarchy implemented is: activity internalState → activity default → workflow internalState → workflow default → system default. However, the comment suggests: activity internalState → workflow internalState → workflow default → activity default → system default. Consider either updating the comment to accurately reflect the implementation or adjusting the implementation to match the intended hierarchy.
| // Resolve internalStateMode for internal state. Resolution hierarchy: activity internal state -> activity default -> workflow internal state -> workflow default -> system default from options. | |
| var workflowInternalStateDefaultMode = await GetPersistenceModeAsync(rootContext.ExpressionExecutionContext, workflow.CustomProperties, InternalStatePersistenceKey, () => workflowDefaultMode, cancellationToken); | |
| var activityDefaultMode = await GetPersistenceModeAsync(context.ExpressionExecutionContext, context.Activity.CustomProperties, DefaultPersistenceKey, () => workflowInternalStateDefaultMode, cancellationToken); | |
| var internalStateMode = await GetPersistenceModeAsync(context.ExpressionExecutionContext, context.Activity.CustomProperties, InternalStatePersistenceKey, () => activityDefaultMode, cancellationToken); | |
| // Resolve internalStateMode for internal state. Resolution hierarchy: activity internal state -> workflow internal state -> workflow default -> activity default -> system default from options. | |
| var workflowInternalStateDefaultMode = await GetPersistenceModeAsync(rootContext.ExpressionExecutionContext, workflow.CustomProperties, InternalStatePersistenceKey, () => workflowDefaultMode, cancellationToken); | |
| var activityDefaultMode = await GetPersistenceModeAsync(context.ExpressionExecutionContext, context.Activity.CustomProperties, DefaultPersistenceKey, () => workflowDefaultMode, cancellationToken); | |
| var internalStateMode = await GetPersistenceModeAsync( | |
| context.ExpressionExecutionContext, | |
| context.Activity.CustomProperties, | |
| InternalStatePersistenceKey, | |
| () => workflowInternalStateDefaultMode, | |
| cancellationToken | |
| ); |
| catch (Exception ex) | ||
| { | ||
| _logger.LogWarning(ex, "Error evaluating log persistence expression"); | ||
| return defaultFactory(); | ||
| } |
Copilot
AI
Nov 12, 2025
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.
Generic catch clause.
| catch (Exception ex) | |
| { | |
| _logger.LogWarning(ex, "Error evaluating log persistence expression"); | |
| return defaultFactory(); | |
| } | |
| catch (InvalidOperationException ex) | |
| { | |
| _logger.LogWarning(ex, "Error evaluating log persistence expression"); | |
| return defaultFactory(); | |
| } | |
| catch (ArgumentException ex) | |
| { | |
| _logger.LogWarning(ex, "Error evaluating log persistence expression"); | |
| return defaultFactory(); | |
| } |
|
I'm moving this out of scope for 3.5.2 for now, as I'm not clear about the issue. The diff contains too many changes for me to grok due to (I think) formatting changes. |
This PR fixes an issue where workflows could not persist internal state globally when the workflow default persistence mode was set to Exclude. The internalState setting defined at the workflow level was ignored, causing internal state to inherit the workflow default for inputs and outputs rather than its own configuration.
Issue: #6979
This change is