22
33namespace ContinuousPipe \MessageBundle \Command ;
44
5+ use ContinuousPipe \Message \MessageConsumer ;
6+ use ContinuousPipe \Message \MessagePuller ;
57use ContinuousPipe \Message \PulledMessage ;
68use Doctrine \Common \Collections \ArrayCollection ;
79use Doctrine \Common \Collections \Collection ;
10+ use Psr \Log \LoggerInterface ;
811use Symfony \Bundle \FrameworkBundle \Command \ContainerAwareCommand ;
912use Symfony \Component \Console \Input \InputInterface ;
1013use Symfony \Component \Console \Output \Output ;
1114use Symfony \Component \Console \Output \OutputInterface ;
1215use Symfony \Component \Process \Process ;
16+ use Tolerance \Operation \ExceptionCatcher \ThrowableCatcherVoter ;
1317
1418class PullAndConsumeMessageCommand extends ContainerAwareCommand
1519{
20+ /**
21+ * Maximum runtime, in seconds. 30 minutes, in order to prevent any database-timeout related issue.
22+ */
23+ const MAX_RUNTIME_IN_SECS = 1800 ;
24+
25+ /**
26+ * @var bool
27+ */
1628 private $ shouldStop = false ;
1729
18- public function configure ()
19- {
20- $ this ->setName ('continuouspipe:message:pull-and-consume ' );
30+ /**
31+ * @var MessagePuller
32+ */
33+ private $ messagePuller ;
34+
35+ /**
36+ * @var MessageConsumer
37+ */
38+ private $ messageConsumer ;
39+
40+ /**
41+ * @var ThrowableCatcherVoter
42+ */
43+ private $ throwableCatcherVoter ;
44+
45+ /**
46+ * @var LoggerInterface
47+ */
48+ private $ logger ;
49+
50+ public function __construct (
51+ MessagePuller $ messagePuller ,
52+ MessageConsumer $ messageConsumer ,
53+ ThrowableCatcherVoter $ throwableCatcherVoter ,
54+ LoggerInterface $ logger
55+ ) {
56+ parent ::__construct ('continuouspipe:message:pull-and-consume ' );
57+
58+ $ this ->messagePuller = $ messagePuller ;
59+ $ this ->messageConsumer = $ messageConsumer ;
60+ $ this ->throwableCatcherVoter = $ throwableCatcherVoter ;
61+ $ this ->logger = $ logger ;
2162 }
2263
2364 public function run (InputInterface $ input , OutputInterface $ output )
2465 {
25- $ puller = $ this ->getContainer ()->get ('continuouspipe.message.message_poller ' );
26- $ consumer = $ this ->getContainer ()->get ('continuouspipe.message.message_consumer ' );
2766 $ consolePath = $ this ->getContainer ()->getParameter ('kernel.root_dir ' ).DIRECTORY_SEPARATOR .'console ' ;
2867
2968 pcntl_signal (SIGTERM , [$ this , 'stopCommand ' ]);
3069 pcntl_signal (SIGINT , [$ this , 'stopCommand ' ]);
3170
3271 $ output ->writeln ('Waiting for messages... ' );
72+ $ startTime = time ();
3373
3474 while (!$ this ->shouldStop ) {
35- foreach ($ puller ->pull () as $ pulledMessage ) {
75+ foreach ($ this -> messagePuller ->pull () as $ pulledMessage ) {
3676 /** @var PulledMessage $pulledMessage */
3777 $ message = $ pulledMessage ->getMessage ();
3878
@@ -41,13 +81,34 @@ public function run(InputInterface $input, OutputInterface $output)
4181 $ extenderProcess = new Process ($ consolePath . ' continuouspipe:message:extend-deadline ' . $ pulledMessage ->getAcknowledgeIdentifier ());
4282 $ extenderProcess ->start ();
4383
44- $ consumer ->consume ($ message );
84+ try {
85+ $ this ->messageConsumer ->consume ($ message );
86+ } catch (\Throwable $ e ) {
87+ // The throwable will be handled later...
88+ $ this ->logger ->warning ('An exception occurred while processing the message ' , [
89+ 'exception ' => $ e ,
90+ ]);
91+ } finally {
92+ $ extenderProcess ->stop (0 );
93+ }
94+
95+ if (isset ($ e ) && $ this ->throwableCatcherVoter ->shouldCatchThrowable ($ e )) {
96+ $ output ->writeln (sprintf ('Message "%s" (%s) has not been acknowledge as the exception has been cought ' , get_class ($ message ), $ pulledMessage ->getIdentifier ()));
97+ } else {
98+ $ output ->writeln (sprintf ('Acknowledging message "%s" (%s) ' , get_class ($ message ), $ pulledMessage ->getIdentifier ()));
99+ $ pulledMessage ->acknowledge ();
100+ }
45101
46- $ output ->writeln (sprintf ('Acknowledging message "%s" (%s) ' , get_class ($ message ), $ pulledMessage ->getIdentifier ()));
47- $ pulledMessage ->acknowledge ();
48- $ extenderProcess ->stop (0 );
49102 $ output ->writeln (sprintf ('Finished consuming message "%s" (%s) ' , get_class ($ message ), $ pulledMessage ->getIdentifier ()));
103+
104+ // If an exception happened, break the loop to ensure to go back to the `shouldStop` condition
105+ if (isset ($ e )) {
106+ break ;
107+ }
50108 }
109+
110+ $ ranMoreThanRunTime = (time () - $ startTime ) > self ::MAX_RUNTIME_IN_SECS ;
111+ $ this ->shouldStop = $ this ->shouldStop || $ ranMoreThanRunTime ;
51112 }
52113
53114 $ output ->writeln ('The worker has stopped (should have stopped: ' .($ this ->shouldStop ? 'yes ' : 'no ' ).') ' );
0 commit comments