Retrieve named send signal channel

I’m trying to find a way to retrieve and use a SendChannel from within a workflow (several function calls deep). Temporal has:

  • workflow.NewNamedChannel, which returns a Channel
  • workflow.GetSignalChannel, which returns a ReceiveChannel (not a Channel or a SendChannel)
  • workflow.SignalExternalWorkflow, which can send a signal to an external workflow

What seems to be missing is a way to retrieve a SendChannel or Channel for use within a workflow. That would be there if either:

  • workflow.GetSignalChannel returned a Channel, instead of a ReceiveChannel or
  • workflow.SignalWorkflow existed to do what SignalExternalWorkflow does, but within the same workflow.

What am I missing here?

Signals are, by definition, external to a workflow. So it doesn’t make sense to send them from within. What is a specific use case you are trying to solve?

I have a DSL-based workflow that uses the concept of “state” and “action”, something like (in Go):

jumpSignalChan := workflow.NewNamedChannel(ctx, "jump")
ctx = workflow.WithValue(ctx, "jumpChannel", jumpSignalChan)

selector := workflow.NewNamedSelector(ctx, "jump")
selector.AddReceive(jumpSignalChan, func(c workflow.ReceiveChannel, more bool) {
	c.Receive(ctx, &nextStateCode)
	jumpRequested = true
})

for stateCode = StartState; stateCode != EndState; stateCode = nextStateCode {
	state = states[stateCode]
	....
	for _, action := range state.Actions {
		workflow.Go(ctx, func(c workflow.Context) {
			nextStateCode, ns, err = action.Body.Eval(ctx, ns, defn, action, nil, workflowID)
			actionFinished = true
		})

		workflow.Await(ctx, func() bool {
			return jumpRequested || actionFinished
		})

		if jumpRequested {
			jumpRequested = false
			break
		}
	}
	..
	if nextStateCode == "" && state.Next != "" {
		nextStateCode = state.Next
	}

So the idea is: evaluate all of the actions in the current state, but if one of them executes a “jump” action, move to the state requested by the jump. It acts like a “goto”. Any of the (possibly recursive) calls to Eval could generate a jump.

You can have a goroutine that forwards requests from the signal channel to the jump channel if needed.

How would I communicate with that Go routine from, say, a call to action.Body.Eval, above? I (mistakenly?) thought that that’s what channels were for?

What is Eval? If it is part of the workflow, it sends to the jump channel directly.

Yes, Eval is part of the workflow. What I’m not understanding is how to get the SendChannel from a workflow module function call. Or should I put it into the workflow context, as my example shows? Or do I need to pass it into the functions that need it? I’m looking for the equivalent of workflow.GetSignalChannel but for SendChannels (or Channels) as opposed to ReceiveChannels.

I would pass it as a constructor argument to the other objects in your DSL.

Workflow is code. So, you use the same techniques you would normally use to pass dependencies.

Okay, that’ll work. Thanks!