18
18
use Illuminate \Queue \InvalidPayloadException ;
19
19
use Illuminate \Queue \Queue ;
20
20
use Illuminate \Support \Arr ;
21
+ use Illuminate \Support \Facades \DB ;
21
22
use Illuminate \Support \Str ;
22
23
use Psr \Log \LoggerInterface ;
23
24
use Stomp \Exception \ConnectionException ;
@@ -33,6 +34,7 @@ class StompQueue extends Queue implements QueueInterface
33
34
const CORRELATION = 'X-Correlation-ID ' ;
34
35
35
36
const ACK_MODE_CLIENT = 'client ' ;
37
+ const ACK_MODE_AUTO = 'auto ' ;
36
38
37
39
/**
38
40
* Stomp instance from stomp-php repo.
@@ -53,8 +55,15 @@ class StompQueue extends Queue implements QueueInterface
53
55
protected int $ circuitBreaker = 0 ;
54
56
protected string $ session ;
55
57
58
+ /** @var null|Frame */
56
59
protected $ _lastFrame = null ;
57
- protected $ _ackMode = 'client ' ;
60
+
61
+ protected string $ _ackMode = '' ;
62
+
63
+ protected array $ _queueNamesForProcessAllQueues = ['' ];
64
+ protected bool $ _customReadQueusDefined = false ;
65
+
66
+ protected bool $ _readMessagesLogToDb = false ;
58
67
59
68
public function __construct (ClientWrapper $ stompClient )
60
69
{
@@ -65,26 +74,31 @@ public function __construct(ClientWrapper $stompClient)
65
74
66
75
$ this ->session = $ this ->client ->getClient ()->getSessionId ();
67
76
68
- $ this ->_ackMode = strtolower (Config::get ('consumer_ack_mode ' ) ?? 'client ' );
77
+ $ this ->_ackMode = strtolower (Config::get ('consumer_ack_mode ' ) ?? self ::ACK_MODE_AUTO );
78
+
79
+ // specify which queue names should be considered as "All queues from Config"
80
+ // "default" & ""
81
+ $ this ->_queueNamesForProcessAllQueues = Config::queueNamesForProcessAllQueues ();
82
+ $ this ->_readMessagesLogToDb = Config::shouldReadMessagesBeLoggedToDB ();
69
83
}
70
84
71
85
/**
72
86
* Append queue name to topic/address to avoid random hashes in broker.
73
87
*
88
+ * @param string|null $queuesString
74
89
* @return array
75
90
*/
76
- protected function setReadQueues (): array
91
+ protected function setReadQueues (? string $ queuesString = '' ): array
77
92
{
78
- $ queues = $ this ->parseQueues (Config::readQueues ());
93
+ $ queuesString = $ queuesString ?: Config::readQueues ();
94
+ $ queues = $ this ->parseQueues ($ queuesString );
79
95
80
96
foreach ($ queues as &$ queue ) {
81
97
$ default = Config::defaultQueue ();
82
-
83
98
if (!str_contains ($ queue , self ::AMQ_QUEUE_SEPARATOR )) {
84
99
$ queue .= self ::AMQ_QUEUE_SEPARATOR . $ default . '_ ' . substr (Str::uuid (), -5 );
85
100
continue ;
86
101
}
87
-
88
102
if (Config::get ('prepend_queues ' )) {
89
103
$ topic = Str::before ($ queue , self ::AMQ_QUEUE_SEPARATOR );
90
104
$ queueName = Str::after ($ queue , self ::AMQ_QUEUE_SEPARATOR );
@@ -218,7 +232,7 @@ protected function writeToMultipleQueues(array $writeQueues, Message $payload):
218
232
$ this ->log ->info ("$ this ->session [STOMP] Pushing stomp payload to queue: " . print_r ([
219
233
'body ' => $ payload ->getBody (),
220
234
'headers ' => $ payload ->getHeaders (),
221
- 'queue ' => $ writeQueues ,
235
+ 'queues ' => $ writeQueues ,
222
236
], true ));
223
237
224
238
$ allEventsSent = true ;
@@ -349,6 +363,8 @@ protected function hasEvent($job): bool
349
363
*/
350
364
public function pop ($ queue = null )
351
365
{
366
+ $ this ->setReadQueuesForWorker ($ queue );
367
+
352
368
$ this ->ackLastFrameIfNecessary ();
353
369
354
370
$ frame = $ this ->read ($ queue );
@@ -366,21 +382,21 @@ public function pop($queue = null)
366
382
$ queueFromFrame = $ this ->getQueueFromFrame ($ frame );
367
383
368
384
if (!$ queueFromFrame ) {
369
- $ this ->log ->error ("$ this ->session [STOMP] Wrong frame received. Expected MESSAGE, got: " . print_r ($ frame , true ));
385
+ $ this ->log ->warning ("$ this ->session [STOMP] Wrong frame received. Expected MESSAGE, got: " . print_r ($ frame , true ));
370
386
$ this ->_lastFrame = null ;
371
387
372
388
return null ;
373
389
}
374
390
375
391
$ this ->_lastFrame = $ frame ;
376
392
393
+ $ this ->writeMessageToDBIfNeeded ($ frame , $ queueFromFrame );
394
+
377
395
return new StompJob ($ this ->container , $ this , $ frame , $ queueFromFrame );
378
396
}
379
397
380
398
protected function read ($ queue )
381
399
{
382
- // This will read from queue, then push on same session ID if there are events following, then delete event which was read
383
- // If job fails, it will be re-pushed on same session ID but with additional headers for redelivery
384
400
try {
385
401
$ this ->log ->info ("$ this ->session [STOMP] POP " );
386
402
@@ -457,7 +473,11 @@ protected function reconnect(bool $subscribe = true)
457
473
458
474
try {
459
475
$ this ->client ->getClient ()->connect ();
476
+ $ newSessionId = $ this ->client ->getClient ()->getSessionId ();
477
+
460
478
$ this ->log ->info ("$ this ->session [STOMP] Reconnected successfully. " );
479
+ $ this ->log ->info ("$ this ->session [STOMP] Switching session to: $ newSessionId " );
480
+ $ this ->session = $ newSessionId ;
461
481
} catch (Exception $ e ) {
462
482
$ this ->circuitBreaker ++;
463
483
@@ -475,7 +495,7 @@ protected function reconnect(bool $subscribe = true)
475
495
}
476
496
477
497
// By this point it should be connected, so it is safe to subscribe
478
- if ($ this ->client ->getClient ()->isConnected () && $ subscribe ) {
498
+ if ($ subscribe && $ this ->client ->getClient ()->isConnected ()) {
479
499
$ this ->log ->info ("$ this ->session [STOMP] Connected, subscribing... " );
480
500
$ this ->subscribedTo = [];
481
501
$ this ->subscribeToQueues ();
@@ -497,23 +517,29 @@ public function disconnect()
497
517
}
498
518
}
499
519
520
+ /**
521
+ * Subscribe to queues.
522
+ *
523
+ * @return void
524
+ */
500
525
protected function subscribeToQueues (): void
501
526
{
527
+ $ winSize = Config::get ('consumer_window_size ' );
528
+ if ($ this ->_ackMode != self ::ACK_MODE_CLIENT ) {
529
+ // New Artemis version can't work without this as it will consume only first message otherwise.
530
+ $ winSize = -1 ;
531
+ }
532
+
502
533
foreach ($ this ->readQueues as $ queue ) {
503
534
$ alreadySubscribed = in_array ($ queue , $ this ->subscribedTo );
504
535
505
536
if ($ alreadySubscribed ) {
506
537
continue ;
507
538
}
508
539
509
- $ winSize = Config::get ('consumer_window_size ' ) ?: 8192000 ;
510
- if ($ this ->_ackMode != self ::ACK_MODE_CLIENT ) {
511
- $ winSize = -1 ;
512
- }
540
+ $ this ->log ->info ("$ this ->session [STOMP] subscribeToQueue ` $ queue` with ack-mode: {$ this ->_ackMode } & window-size: $ winSize " );
513
541
514
542
$ this ->client ->subscribe ($ queue , null , $ this ->_ackMode , [
515
- // New Artemis version can't work without this as it will consume only first message otherwise.
516
- //'consumer-window-size' => '-1',
517
543
// we can define this if we are using ack mode = client
518
544
'consumer-window-size ' => (string ) $ winSize ,
519
545
]);
@@ -530,8 +556,48 @@ protected function subscribeToQueues(): void
530
556
public function ackLastFrameIfNecessary ()
531
557
{
532
558
if ($ this ->_ackMode == self ::ACK_MODE_CLIENT && $ this ->_lastFrame ) {
559
+ $ this ->log ->debug ("$ this ->session [STOMP] ACK-ing last frame. Msg # " . $ this ->_lastFrame ->getMessageId ());
533
560
$ this ->client ->ack ($ this ->_lastFrame );
534
561
$ this ->_lastFrame = null ;
535
562
}
536
563
}
564
+
565
+ /**
566
+ * Set read queues for queue worker, if queue parameter is defined
567
+ * > php artisan queue:work --queue=eloquent::live30.
568
+ *
569
+ * @param $queue
570
+ * @return void
571
+ */
572
+ protected function setReadQueuesForWorker ($ queue )
573
+ {
574
+ if ($ this ->_customReadQueusDefined ) {
575
+ // already setup
576
+ return ;
577
+ }
578
+
579
+ $ queue = (string ) $ queue ;
580
+ if (!in_array ($ queue , $ this ->_queueNamesForProcessAllQueues )) {
581
+ // one or more queue
582
+ $ this ->readQueues = $ this ->setReadQueues ($ queue );
583
+ }
584
+
585
+ $ this ->_customReadQueusDefined = true ;
586
+ }
587
+
588
+ protected function writeMessageToDBIfNeeded (Frame $ frame , $ queueFromFrame )
589
+ {
590
+ if ($ this ->_readMessagesLogToDb ) {
591
+ DB ::table ('stomp_event_logs ' )->insert (
592
+ [
593
+ 'session_id ' => $ this ->session ,
594
+ 'queue_name ' => $ queueFromFrame ,
595
+ 'subscription_id ' => $ frame ['subscription ' ],
596
+ 'message_id ' => $ frame ->getMessageId (),
597
+ 'payload ' => print_r ($ frame , true ),
598
+ 'created_at ' => date ('Y-m-d H:i:s.u ' ),
599
+ ]
600
+ );
601
+ }
602
+ }
537
603
}
0 commit comments