feat(temporal): detect outbound signal-send / query-call against running workflows#81
Merged
Merged
Conversation
…ing workflows
Surface the consumer side of the Temporal signal/query namespaces:
workflow.SignalExternalWorkflow(ctx, wid, rid, "name", arg) // workflow -> workflow
client.SignalWorkflow(ctx, wid, rid, "name", arg) // service -> workflow
client.QueryWorkflow(ctx, wid, rid, "name", args...) // service -> workflow
Each emits an EdgeCalls edge tagged via=temporal.signal-send /
temporal.query-call carrying temporal_kind + temporal_name (the signal /
query name = the 4th positional argument, a string literal). These pair
with the in-workflow handler edges (via=temporal.handler) as the
sender/handler two sides of the signal/query contract.
SignalExternalWorkflow is gated on the canonical "workflow" receiver;
SignalWorkflow / QueryWorkflow live on the client and are matched by
method name (like the Register* helpers), kept high-precision by the
string-literal name gate. No new edge kinds — consistent with the
existing EdgeCalls + via=temporal.* convention.
Note on the Go SDK surface: there is no workflow.SetSignalHandler
(signals are received via GetSignalChannel), no workflow.QueryWorkflow
(querying is client-side), and no SignalExternalWorkflowAsync
(SignalExternalWorkflow already returns a Future).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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
Detect the consumer side of the Temporal signal/query namespaces — code that signals or queries an already-running workflow by name — and surface it as graph edges. This complements the in-workflow handler edges (
via=temporal.handler, added in #78) with the matching sender/caller side.Changes
Recognises three call shapes and tags the emitted
EdgeCallsedge:workflow.SignalExternalWorkflow(ctx, wid, rid, "name", arg)(workflow → workflow)temporal.signal-sendsignalclient.SignalWorkflow(ctx, wid, rid, "name", arg)(service → workflow)temporal.signal-sendsignalclient.QueryWorkflow(ctx, wid, rid, "name", args...)(service → workflow)temporal.query-callqueryThe signal/query name is the 4th positional argument and must be a string literal (names are matched by string at runtime, so a variable/constant is left undetected — high-precision, consistent with the existing detectors).
SignalExternalWorkflowis gated on the canonicalworkflowreceiver;SignalWorkflow/QueryWorkfloware client methods called on an arbitrary client variable, so they're matched by method name (the same precedent as theRegister*helpers), kept precise by the string-literal name gate.No new edge/node kinds — stays on the established
EdgeCalls+via=temporal.*meta convention, so blast-radius/impact already traverse these generically.A note on the Go SDK surface (API corrections)
While implementing this I verified the API against
go.temporal.io/sdkand corrected a few things that don't exist in the Go SDK:workflow.SetSignalHandler— signals are received viaGetSignalChannel(already detected). The genuinely-missing handler variants (SetQueryHandlerWithOptions,GetSignalChannelWithOptions) are added in feat(temporal): detect Go in-workflow query/signal/update handler declarations #78, not here.workflow.QueryWorkflow— querying is a client-side operation (Client.QueryWorkflow), handled accordingly above.SignalExternalWorkflowAsync—SignalExternalWorkflowalready returns aFuture.Testing
go test ./...) for the touched package (internal/parser/languages);golangci-lint v2.11.4 run --timeout=10m→ 0 issues.SignalExternalWorkflow,client.SignalWorkflow,client.QueryWorkflow, plus negatives for a non-literal name and an aliased-importSignalExternalWorkflow.Checklist
applyGoTemporalRegisterMeta; matches theRegister*receiver-agnostic precedent with a literal-arg precision gate)Meta["methods"]for interfaces (if applicable) — n/aEdgeMemberOfedges to their containing type (if applicable) — n/aRelation to other PRs
Part of a small in-grain Temporal series, all independent and reviewable separately: #78 (in-workflow query/signal/update handler edges), #79 (env-var-with-default dispatch names), and this one. The larger cross-language Java→Go bridge and a couple of foundational engine questions are discussed in #77 and #80.