@@ -210,8 +210,11 @@ mutable struct MessageConsumer
210
210
callback:: Function
211
211
receiver:: Task
212
212
213
- function MessageConsumer (chan_id:: TAMQPChannel , consumer_tag:: String , callback:: Function ; buffer_size:: Int = typemax (Int))
214
- c = new (chan_id, consumer_tag, Channel {Message} (buffer_size), callback)
213
+ function MessageConsumer (chan_id:: TAMQPChannel , consumer_tag:: String , callback:: Function ;
214
+ buffer_size:: Int = typemax (Int),
215
+ buffer:: Channel{Message} = Channel {Message} (buffer_size))
216
+
217
+ c = new (chan_id, consumer_tag, buffer, callback)
215
218
c. receiver = @async connection_processor (c, " Consumer $consumer_tag " , channel_message_consumer)
216
219
c
217
220
end
@@ -232,14 +235,16 @@ mutable struct MessageChannel <: AbstractChannel
232
235
partial_msgs:: Vector{Message} # holds partial messages while they are getting read (message bodies arrive in sequence)
233
236
chan_get:: Channel{Union{Message, Nothing}} # channel used for received messages, in sync get call (TODO : maybe type more strongly?)
234
237
consumers:: Dict{String,MessageConsumer}
238
+ pending_msgs:: Dict{String,Channel{Message}} # holds messages received that do not have a consumer registered
239
+ lck:: ReentrantLock
235
240
236
241
closereason:: Union{CloseReason, Nothing}
237
242
238
243
function MessageChannel (id, conn)
239
244
new (id, conn, CONN_STATE_CLOSED, true ,
240
245
Channel {TAMQPGenericFrame} (CONN_MAX_QUEUED), nothing , Dict {Tuple,Tuple{Function,Any}} (),
241
246
Message[], Channel {Union{Message, Nothing}} (1 ), Dict {String,MessageConsumer} (),
242
- nothing )
247
+ Dict {String,Channel{Message}} (), ReentrantLock (), nothing )
243
248
end
244
249
end
245
250
422
427
clear_handlers (c:: MessageChannel ) = (empty! (c. callbacks); nothing )
423
428
function handle (c:: MessageChannel , classname:: Symbol , methodname:: Symbol , cb= nothing , ctx= nothing )
424
429
cbkey = method_key (classname, methodname)
425
- if cb == nothing
430
+ if cb === nothing
426
431
delete! (c. callbacks, cbkey)
427
432
else
428
433
c. callbacks[cbkey] = (cb, ctx)
@@ -431,7 +436,7 @@ function handle(c::MessageChannel, classname::Symbol, methodname::Symbol, cb=not
431
436
end
432
437
function handle (c:: MessageChannel , frame_type:: Integer , cb= nothing , ctx= nothing )
433
438
cbkey = frame_key (frame_type)
434
- if cb == nothing
439
+ if cb === nothing
435
440
delete! (c. callbacks, cbkey)
436
441
else
437
442
c. callbacks[cbkey] = (cb, ctx)
@@ -779,15 +784,28 @@ nowait: do not send a reply method
779
784
"""
780
785
function basic_consume (chan:: MessageChannel , queue:: String , consumer_fn:: Function ; consumer_tag:: String = " " , no_local:: Bool = false , no_ack:: Bool = false ,
781
786
exclusive:: Bool = false , nowait:: Bool = false , arguments:: Dict{String,Any} = Dict {String,Any} (), timeout:: Int = DEFAULT_TIMEOUT, buffer_sz:: Int = typemax (Int))
787
+
788
+ # register the consumer and get the consumer_tag
782
789
result = _wait_resp (chan, (true , " " ), nowait, on_basic_consume_ok, :Basic , :ConsumeOk , (false , " " ), timeout) do
783
790
send_basic_consume (chan, queue, consumer_tag, no_local, no_ack, exclusive, nowait, arguments)
784
791
end
785
792
786
- # setup a message consumer
793
+ # start the message consumer
787
794
if result[1 ]
788
795
consumer_tag = result[2 ]
789
- chan. consumers[consumer_tag] = MessageConsumer (chan. id, consumer_tag, consumer_fn; buffer_size= buffer_sz)
796
+
797
+ # set up message buffer beforehand to store messages that the consumer may receive while we are still setting things up,
798
+ # or get the buffer that was set up already because we received messages
799
+ lock (chan. lck) do
800
+ consumer_buffer = get! (chan. pending_msgs, consumer_tag) do
801
+ Channel {Message} (buffer_sz)
802
+ end
803
+ consumer_buffer. sz_max = buffer_sz
804
+ chan. consumers[consumer_tag] = MessageConsumer (chan. id, consumer_tag, consumer_fn; buffer= consumer_buffer)
805
+ delete! (chan. pending_msgs, consumer_tag)
806
+ end
790
807
end
808
+
791
809
result
792
810
end
793
811
@@ -1177,15 +1195,15 @@ function on_basic_get_empty_or_ok(chan::MessageChannel, m::TAMQPMethodFrame, ctx
1177
1195
end
1178
1196
1179
1197
function on_channel_message_in (chan:: MessageChannel , m:: TAMQPContentHeaderFrame , ctx)
1180
- msg = chan. partial_msgs[ 1 ]
1198
+ msg = last ( chan. partial_msgs)
1181
1199
msg. properties = m. hdrpayload. proplist
1182
1200
msg. data = Vector {UInt8} (undef, m. hdrpayload. bodysize)
1183
1201
msg. filled = 0
1184
1202
nothing
1185
1203
end
1186
1204
1187
1205
function on_channel_message_in (chan:: MessageChannel , m:: TAMQPContentBodyFrame , ctx)
1188
- msg = chan. partial_msgs[ 1 ]
1206
+ msg = last ( chan. partial_msgs)
1189
1207
data = m. payload. data
1190
1208
startpos = msg. filled + 1
1191
1209
endpos = min (length (msg. data), msg. filled + length (data))
@@ -1195,11 +1213,16 @@ function on_channel_message_in(chan::MessageChannel, m::TAMQPContentBodyFrame, c
1195
1213
if msg. filled >= length (msg. data)
1196
1214
# got all data for msg
1197
1215
if isempty (msg. consumer_tag)
1198
- put! (chan. chan_get, popfirst! (chan. partial_msgs))
1199
- elseif msg. consumer_tag in keys (chan. consumers)
1200
- put! (chan. consumers[msg. consumer_tag]. recvq, popfirst! (chan. partial_msgs))
1216
+ put! (chan. chan_get, pop! (chan. partial_msgs))
1201
1217
else
1202
- @debug (" discarding message, no consumer with tag" , tag= msg. consumer_tag)
1218
+ lock (chan. lck) do
1219
+ if msg. consumer_tag in keys (chan. consumers)
1220
+ put! (chan. consumers[msg. consumer_tag]. recvq, pop! (chan. partial_msgs))
1221
+ else
1222
+ put! (get! (()-> Channel {Message} (typemax (Int)), chan. pending_msgs, msg. consumer_tag), msg)
1223
+ @debug (" holding message, no consumer yet with tag" , tag= msg. consumer_tag)
1224
+ end
1225
+ end
1203
1226
end
1204
1227
end
1205
1228
@@ -1210,6 +1233,4 @@ on_confirm_select_ok(chan::MessageChannel, m::TAMQPMethodFrame, ctx) = _on_ack(c
1210
1233
1211
1234
# ----------------------------------------
1212
1235
# send and recv for methods end
1213
- # ----------------------------------------
1214
-
1215
-
1236
+ # ----------------------------------------
0 commit comments