feat(temporal): Go in-workflow query/signal/update handlers + env-default dispatch names#75
Closed
avfirsov wants to merge 3 commits into
Closed
Conversation
…larations Surface workflow.SetQueryHandler / GetSignalChannel / SetUpdateHandler[WithOptions] calls as via=temporal.handler EdgeCalls edges carrying temporal_kind (query/signal/update) + temporal_name, originating from the enclosing workflow function. This mirrors the Java side's per-method @QueryMethod / @SignalMethod / @UpdateMethod annotation edges, giving the graph a symmetric, queryable record of the named handlers each Go workflow exposes. High-precision: only the canonical "workflow" receiver alias is matched and the handler name must be a string literal (runtime-matched names can't be pinned from a variable), consistent with the existing dispatch detector. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ault vars
When a workflow names its activity/child-workflow through a local variable
read from an env var with a literal fallback, resolve the dispatch to that
literal default instead of leaving it unresolved:
actName := cmp.Or(os.Getenv("CHARGE_ACTIVITY"), "ChargeCard")
workflow.ExecuteActivity(ctx, actName, id) // -> activity "ChargeCard"
name := os.Getenv("K"); if name == "" { name = "ChargeCard" }
The parser does a narrow, intra-procedural lookup anchored on a literal
os.Getenv / os.LookupEnv read (so the value is provably env-sourced, not a
general data-flow guess) and tags the stub edge temporal_name_origin=
env_default. The resolver then lands the edge at the speculative tier
(OriginSpeculative, confidence 0.4, MetaSpeculative=true) rather than
ast_resolved — the runtime env override may name a different handler than
the literal default, so the edge is present but hidden from default queries.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The G4 refactor routed dispatch-name extraction through goTemporalDispatchArg + goTemporalNameFromExpr, leaving goTemporalDispatchName with no call sites. golangci-lint's 'unused' linter (not caught by local 'go vet') flagged it. Fold its doc into goTemporalDispatchArg and remove the dead wrapper. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 12, 2026
Contributor
Author
|
Split into two focused PRs so each can be reviewed/merged independently:
Closing this combined PR in favour of those two. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two small, independent additions to the Temporal Go extractor/resolver, each mirroring an existing pattern in the codebase. They close two gaps in the Go-side Temporal surface; the larger cross-language Java→Go bridge is proposed separately for design discussion in #77 (not in this PR).
The two commits are independent and can be reviewed / merged / split separately.
Changes
1. Detect in-workflow query/signal/update handler declarations (
feat(temporal): detect Go in-workflow query/signal/update handler declarations)workflow.SetQueryHandler/GetSignalChannel/SetUpdateHandler[WithOptions]and emits avia=temporal.handlerEdgeCallsedge from the enclosing workflow carryingtemporal_kind(query/signal/update) +temporal_name.via=temporal.register/via=temporal.stubemission exactly, and gives the graph a symmetric, queryable record of the named handlers a Go workflow exposes — the Go counterpart to the Java side's@QueryMethod/@SignalMethod/@UpdateMethodannotation edges.workflowreceiver alias matches and the handler name must be a string literal (runtime-matched names can't be pinned from a variable), consistent with the existing dispatch detector.2. Resolve activity/workflow names from env-var-with-default variables (
feat(temporal): resolve activity/workflow names from env-var-with-default vars)os.Getenv/os.LookupEnvread (so the value is provably env-sourced — not general constant propagation), and only considers assignments lexically before the call.OriginSpeculative, confidence0.4,MetaSpeculative=true) rather thanast_resolved— the runtime env override may name a different handler than the literal default, so the edge is present but hidden from default queries, reusing the existing speculative-edge convention.Testing
go test -race ./...) — for the touched packages (internal/parser/languages,internal/resolver,internal/indexertemporal suites). The only failures in my environment are theinternal/indexerwatcher tests failing withinotify ... too many open files(a WSL fd-limit issue, unrelated — no watcher files are touched).go_temporal_test.go), resolver-level (temporal_calls_test.go), and end-to-end (temporal_e2e_test.go) for both features, including negative cases (non-literal handler name, plain non-env variable, env read with no literal default, unresolved-stays-placeholder).Checklist
applyGoTemporalRegisterMeta, the speculative-dispatch tier, the existing detector's high-precision stance)Meta["methods"]for interfaces (if applicable) — n/a, no interface extraction changedEdgeMemberOfedges to their containing type (if applicable) — n/aNotes for reviewers
@WorkflowInterfacestart to the Go workflow / a Java@QueryMethodto the GoSetQueryHandlerprovider added here) raises edge-model and confidence-tier design questions, so it's filed as Cross-language Java→Go Temporal linking (starts_temporal_workflow by canonical name) #77 rather than bundled here.workflowreceiver is matched) is preserved and pinned by a test, consistent with the existing dispatch detector.