@@ -50,22 +50,38 @@ type (
5050 //
5151 // Use workflow.NewChannel(ctx) to create an unbuffered Channel instance,
5252 // workflow.NewBufferedChannel(ctx, size) to create a Channel which has a buffer,
53- // or workflow.GetSignalChannel(ctx, "name") to get a Channel that can contain encoded data sent from other systems.
54- //
55- // workflow.GetSignalChannel is named differently because you are not "creating" a new channel. Signal channels
56- // are conceptually singletons that exist at all times, and they do not have to be "created" before a signal can be
57- // sent to a workflow. The workflow will just have no way to know that the data exists until it inspects the
58- // appropriate signal channel.
53+ // or workflow.GetSignalChannel(ctx, "name") to get a Channel that contains data sent to this workflow by a call to
54+ // SignalWorkflow (e.g. on the Client, or similar methods like SignalExternalWorkflow or SignalChildWorkflow).
5955 //
6056 // Both NewChannel and NewBufferedChannel have "Named" constructors as well.
6157 // These names will be visible in stack-trace queries, so they can help with debugging, but they do not otherwise
6258 // impact behavior at all, and are not recorded anywhere (so you can change them without versioning your code).
59+ //
60+ // Also note that channels created by NewChannel and NewBufferedChannel do not do any serialization or
61+ // deserialization - you will receive whatever value was sent, and non-(de)serializable values like function
62+ // references and interfaces are fine, the same as using a normal Go channel.
63+ //
64+ // Signal channels, however, contain whatever bytes were sent to your workflow, and the values must be decoded into
65+ // the output value. By default, this means that Receive(ctx, &out) will use json.Unmarshal(data, &out), but this
66+ // can be overridden at a worker level (worker.Options) or at a context level (workflow.WithDataConverter(ctx, dc)).
67+ //
68+ // You are able to send values to your own signal channels, and these values will behave the same as they do in
69+ // normal channels (i.e. they will not be (de)serialized). However, doing so is not generally recommended, as
70+ // mixing the value types can increase the risk that you fail to read a value, causing values to be lost. See
71+ // Receive for more details about that behavior.
6372 Channel interface {
6473 // Receive blocks until it receives a value, and then assigns the received value to the provided pointer.
65- // It returns false when Channel is closed and all data has already been consumed from the channel , in the same
66- // way as Go channel reads work.
74+ // It returns false when the Channel is closed and all data has already been consumed from the Channel , in the
75+ // same way as Go channel reads work, but the assignment only occurs if there was a value in the Channel .
6776 //
68- // This is equivalent to `v, more := <- aChannel`.
77+ // This is technically equivalent to:
78+ // received, ok := <- aChannel:
79+ // if ok {
80+ // *valuePtr = received
81+ // }
82+ //
83+ // But if your output values are zero values, this is equivalent to a normal channel read:
84+ // value, ok <- aChannel
6985 //
7086 // valuePtr must be assignable, and will be used to assign (for in-memory data in regular channels) or decode
7187 // (for signal channels) the data in the channel.
@@ -83,36 +99,69 @@ type (
8399 // decoding will be attempted, so you can try it yourself.
84100 // - for other channels, an interface{} pointer. All values are interfaces, so this will never fail, and you
85101 // can inspect the type with reflection or type assertions.
86- Receive (ctx Context , valuePtr interface {}) (more bool )
102+ Receive (ctx Context , valuePtr interface {}) (ok bool )
87103
88- // ReceiveAsync tries to receive from Channel without blocking.
104+ // ReceiveAsync tries to Receive from Channel without blocking.
89105 // If there is data available from the Channel, it assigns the data to valuePtr and returns true.
90106 // Otherwise, it returns false immediately.
91107 //
92- // This is equivalent to:
108+ // This is technically equivalent to:
93109 // select {
94- // case v := <- aChannel: ok = true
95- // default: ok = false
110+ // case received, ok := <- aChannel:
111+ // if ok {
112+ // *valuePtr = received
113+ // }
114+ // default:
115+ // // no value was read
116+ // ok = false
117+ // }
118+ //
119+ // But if your output values are zero values, this is equivalent to a simpler form:
120+ // select {
121+ // case value, ok := <- aChannel:
122+ // default:
123+ // // no value was read
124+ // ok = false
96125 // }
97126 //
98127 // Decoding or assigning failures are handled like Receive.
99128 ReceiveAsync (valuePtr interface {}) (ok bool )
100129
101130 // ReceiveAsyncWithMoreFlag is the same as ReceiveAsync, with an extra return to indicate if there could be
102- // more value from the Channel. more is false when Channel is closed.
131+ // more values from the Channel in the future.
132+ // `more` is false only when Channel is closed and the read failed (empty).
103133 //
104- // This is equivalent to:
134+ // This is technically equivalent to:
105135 // select {
106- // case v, more := <- aChannel: ok = true
107- // default: ok = false
136+ // case received, ok := <- aChannel:
137+ // if ok {
138+ // *valuePtr = received
139+ // }
140+ // more = ok
141+ // default:
142+ // // no value was read
143+ // ok = false
144+ // // but the read would have blocked, so the channel is not closed
145+ // more = true
146+ // }
147+ //
148+ // But if your output values are zero values, this is equivalent to a simpler form:
149+ // select {
150+ // case value, ok := <- aChannel:
151+ // more = ok
152+ // default:
153+ // // no value was read
154+ // ok = false
155+ // // but the read would have blocked, so the channel is not closed
156+ // more = true
108157 // }
109158 //
110159 // Decoding or assigning failures are handled like Receive.
111160 ReceiveAsyncWithMoreFlag (valuePtr interface {}) (ok bool , more bool )
112161
113162 // Send blocks until the data is sent.
114163 //
115- // This is equivalent to `aChannel <- v`
164+ // This is equivalent to `aChannel <- v`.
116165 Send (ctx Context , v interface {})
117166
118167 // SendAsync will try to send without blocking.
@@ -137,20 +186,16 @@ type (
137186 // The interface is intended to simulate Go's select statement, and any Go select can be fairly trivially rewritten
138187 // for a Selector with effectively identical behavior.
139188 //
140- // For example, normal Go code like below:
189+ // For example, normal Go code like below (which will receive values forever, until idle for an hour) :
141190 // chA := make(chan int)
142191 // chB := make(chan int)
143192 // counter := 0
144193 // for {
145194 // select {
146- // case i, more := <- chA:
147- // if more {
148- // counter += i
149- // }
150- // case i, more := <- chB:
151- // if more {
152- // counter += i
153- // }
195+ // case x := <- chA:
196+ // counter += i
197+ // case y := <- chB:
198+ // counter += i
154199 // case <- time.After(time.Hour):
155200 // break
156201 // }
@@ -163,18 +208,14 @@ type (
163208 // timedout := false
164209 // s := workflow.NewSelector(ctx)
165210 // s.AddReceive(chA, func(c workflow.Channel, more bool) {
166- // if more {
167- // var i int
168- // c.Receive(ctx, &i)
169- // counter += i
170- // }
211+ // var x int
212+ // c.Receive(ctx, &x)
213+ // counter += i
171214 // })
172215 // s.AddReceive(chB, func(c workflow.Channel, more bool) {
173- // if more {
174- // var i int
175- // c.Receive(ctx, &i)
176- // counter += i
177- // }
216+ // var y int
217+ // c.Receive(ctx, &y)
218+ // counter += i
178219 // })
179220 // s.AddFuture(workflow.NewTimer(ctx, time.Hour), func(f workflow.Future) {
180221 // timedout = true
@@ -195,25 +236,29 @@ type (
195236 // Context used to construct the Selector, or the Context used to Select, will not (directly) unblock a Select call.
196237 // Read Select for more details.
197238 Selector interface {
198- // AddReceive waits to until a value can be received from a channel.
239+ // AddReceive waits until a value can be received from a channel.
199240 // f is invoked when the channel has data or is closed.
200241 //
201- // This is equivalent to `case v, more := <- aChannel`, and `more ` will only
202- // be false when the channel is both closed and no data was received.
242+ // This is equivalent to `case v, ok := <- aChannel`, and `ok ` will only be false when
243+ // the channel is both closed and no data was received.
203244 //
204245 // When f is invoked, the data (or closed state) remains untouched in the channel, so
205246 // you need to `c.Receive(ctx, &out)` (or `c.ReceiveAsync(&out)`) to remove and decode the value.
206247 // Failure to do this is not an error - the value will simply remain in the channel until a future
207248 // Receive retrieves it.
208- AddReceive (c Channel , f func (c Channel , more bool )) Selector
249+ //
250+ // The `ok` argument will match what a call to c.Receive would return (on a successful read), so it
251+ // may be used to check for closed + empty channels without needing to try to read from the channel.
252+ // See Channel.Receive for additional details about reading from channels.
253+ AddReceive (c Channel , f func (c Channel , ok bool )) Selector
209254 // AddSend waits to send a value to a channel.
210255 // f is invoked when the value was successfully sent to the channel.
211256 //
212257 // This is equivalent to `case aChannel <- value`.
213258 //
214259 // Unlike AddReceive, the value has already been sent on the channel when f is invoked.
215260 AddSend (c Channel , v interface {}, f func ()) Selector
216- // AddFuture invokes f after a Future is ready.
261+ // AddFuture waits until a Future is ready, and then invokes f only once .
217262 // If the Future is ready before Select is called, it is eligible to be invoked immediately.
218263 //
219264 // There is no direct equivalent in a native Go select statement.
0 commit comments