Skip to content

Conversation

jamieQ
Copy link
Contributor

@jamieQ jamieQ commented Mar 26, 2025

refactors action propagation to no longer instantiate any WorkflowDebugInfo types unless there is a WorkflowDebugger set on the host. this should avoid some unnecessary string allocations and reflection metadata lookups.

Checklist

  • Unit Tests
  • UI Tests
  • Snapshot Tests (iOS only)
  • I have made corresponding changes to the documentation

@jamieQ jamieQ force-pushed the jquadri/conditional-dbg-info branch from be86bd7 to 092977f Compare March 26, 2025 21:53
workflowType: "\(WorkflowType.self)",
kind: .didUpdate(source: .external)
)
debugInfo: context.ifDebuggerEnabled {
Copy link
Contributor

Choose a reason for hiding this comment

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

clever!

Copy link
Contributor Author

@jamieQ jamieQ left a comment

Choose a reason for hiding this comment

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

made these changes in a non-breaking way. IMO the current manifestation of the WorkflowDebugger API has not seemed to provide a ton of value for us internally. it might be worth considering removing it in the next major version bump, which would allow some of this code to be cleaned up.

Comment on lines +145 to +149
func toDebugInfoSource() -> WorkflowUpdateDebugInfo.Source {
switch self {
case .external: .external
case .subtree(let maybeInfo): .subtree(maybeInfo.unwrappedOrErrorDefault)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

the other two cases of debug info source (worker and sideeffect) seemed to never have been provided here AFAICT, so we only bother representing the other two cases in the new type.

extension WorkflowNode.SubtreeManager {
enum Output {
case update(any WorkflowAction<WorkflowType>, source: WorkflowUpdateDebugInfo.Source)
case childDidUpdate(WorkflowUpdateDebugInfo)
case update(any WorkflowAction<WorkflowType>, source: EventSource)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

changed this from using the public type to a new internal one

}

extension WorkflowUpdateDebugInfo {
fileprivate static let unexpectedlyMissing = {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

in a few places we want to propagate debug info with the 'right' optionality. either it should be nil if there's no debugger, or non-nil if there is. at the root level we need to emit a value to the debugger if present that is non-optional, hence this 'sanity check' value that will hopefully ensure we don't mess things up.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is there an integration test we could write to validate this behavior, or some other mechanism to solidify this contract?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i added a few more unit tests to cover the 'set a debugger' and 'didn't set a debugger' cases

@jamieQ jamieQ marked this pull request as ready for review April 1, 2025 20:19
@jamieQ jamieQ requested a review from a team as a code owner April 1, 2025 20:19
Copy link
Collaborator

@watt watt left a comment

Choose a reason for hiding this comment

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

this should avoid some unnecessary string allocations and reflection metadata lookups

Did you verify that there's a performance improvement, or is this theoretical?


func test_conditional_debug_info_with_debugger() {
let subject = HostContext.testing(debugger: TestDebugger())
let expectaiton = expectation(description: "debugger block invoked")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
let expectaiton = expectation(description: "debugger block invoked")
let expectation = expectation(description: "debugger block invoked")

Did you know you can turn on spellcheck in Xcode?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ha... yes i do, and (perhaps surprisingly) do in fact have that setting enabled. guess i was not paying very close attention...

@jamieQ
Copy link
Contributor Author

jamieQ commented Apr 2, 2025

Did you verify that there's a performance improvement, or is this theoretical?

it's largely theoretical, and i'd expect any 'real world' gains to be small and amortized, but the code we're currently always running does call runtime functions to produce strings from types, which is not the cheapest thing ever. i did a rough sanity check locally when applying an action through a nested chain of workflows 1000 nodes long, and it appeared consistently faster to skip the debug info creation if not needed.

@jamieQ jamieQ merged commit a303423 into main Apr 2, 2025
7 checks passed
@jamieQ jamieQ deleted the jquadri/conditional-dbg-info branch April 2, 2025 15:21
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.

5 participants