@@ -50,22 +50,38 @@ type (
50
50
//
51
51
// Use workflow.NewChannel(ctx) to create an unbuffered Channel instance,
52
52
// 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).
59
55
//
60
56
// Both NewChannel and NewBufferedChannel have "Named" constructors as well.
61
57
// These names will be visible in stack-trace queries, so they can help with debugging, but they do not otherwise
62
58
// 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.
63
72
Channel interface {
64
73
// 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 .
67
76
//
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
69
85
//
70
86
// valuePtr must be assignable, and will be used to assign (for in-memory data in regular channels) or decode
71
87
// (for signal channels) the data in the channel.
@@ -83,36 +99,69 @@ type (
83
99
// decoding will be attempted, so you can try it yourself.
84
100
// - for other channels, an interface{} pointer. All values are interfaces, so this will never fail, and you
85
101
// 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 )
87
103
88
- // ReceiveAsync tries to receive from Channel without blocking.
104
+ // ReceiveAsync tries to Receive from Channel without blocking.
89
105
// If there is data available from the Channel, it assigns the data to valuePtr and returns true.
90
106
// Otherwise, it returns false immediately.
91
107
//
92
- // This is equivalent to:
108
+ // This is technically equivalent to:
93
109
// 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
96
125
// }
97
126
//
98
127
// Decoding or assigning failures are handled like Receive.
99
128
ReceiveAsync (valuePtr interface {}) (ok bool )
100
129
101
130
// 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).
103
133
//
104
- // This is equivalent to:
134
+ // This is technically equivalent to:
105
135
// 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
108
157
// }
109
158
//
110
159
// Decoding or assigning failures are handled like Receive.
111
160
ReceiveAsyncWithMoreFlag (valuePtr interface {}) (ok bool , more bool )
112
161
113
162
// Send blocks until the data is sent.
114
163
//
115
- // This is equivalent to `aChannel <- v`
164
+ // This is equivalent to `aChannel <- v`.
116
165
Send (ctx Context , v interface {})
117
166
118
167
// SendAsync will try to send without blocking.
@@ -137,20 +186,16 @@ type (
137
186
// The interface is intended to simulate Go's select statement, and any Go select can be fairly trivially rewritten
138
187
// for a Selector with effectively identical behavior.
139
188
//
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) :
141
190
// chA := make(chan int)
142
191
// chB := make(chan int)
143
192
// counter := 0
144
193
// for {
145
194
// 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
154
199
// case <- time.After(time.Hour):
155
200
// break
156
201
// }
@@ -163,18 +208,14 @@ type (
163
208
// timedout := false
164
209
// s := workflow.NewSelector(ctx)
165
210
// 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
171
214
// })
172
215
// 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
178
219
// })
179
220
// s.AddFuture(workflow.NewTimer(ctx, time.Hour), func(f workflow.Future) {
180
221
// timedout = true
@@ -195,25 +236,29 @@ type (
195
236
// Context used to construct the Selector, or the Context used to Select, will not (directly) unblock a Select call.
196
237
// Read Select for more details.
197
238
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.
199
240
// f is invoked when the channel has data or is closed.
200
241
//
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.
203
244
//
204
245
// When f is invoked, the data (or closed state) remains untouched in the channel, so
205
246
// you need to `c.Receive(ctx, &out)` (or `c.ReceiveAsync(&out)`) to remove and decode the value.
206
247
// Failure to do this is not an error - the value will simply remain in the channel until a future
207
248
// 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
209
254
// AddSend waits to send a value to a channel.
210
255
// f is invoked when the value was successfully sent to the channel.
211
256
//
212
257
// This is equivalent to `case aChannel <- value`.
213
258
//
214
259
// Unlike AddReceive, the value has already been sent on the channel when f is invoked.
215
260
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 .
217
262
// If the Future is ready before Select is called, it is eligible to be invoked immediately.
218
263
//
219
264
// There is no direct equivalent in a native Go select statement.
0 commit comments