@@ -486,23 +486,30 @@ Deploying to Production
486486
487487On production, there are a few important things to think about:
488488
489- **Use Supervisor to keep your worker(s) running **
489+ **Use a Process Manager like Supervisor or systemd to keep your worker(s) running **
490490 You'll want one or more "workers" running at all times. To do that, use a
491- process control system like :ref: `Supervisor <messenger-supervisor >`.
491+ process control system like :ref: `Supervisor <messenger-supervisor >`
492+ or :ref: `systemd <messenger-systemd >`.
492493
493494**Don't Let Workers Run Forever **
494495 Some services (like Doctrine's ``EntityManager ``) will consume more memory
495496 over time. So, instead of allowing your worker to run forever, use a flag
496497 like ``messenger:consume --limit=10 `` to tell your worker to only handle 10
497- messages before exiting (then Supervisor will create a new process). There
498+ messages before exiting (then the process manager will create a new process). There
498499 are also other options like ``--memory-limit=128M `` and ``--time-limit=3600 ``.
499500
501+ **Stopping Workers That Encounter Errors **
502+ If a worker dependency like your database server is down, or timeout is reached,
503+ you can try to add :ref: `reconnect logic <middleware-doctrine >`, or just quit
504+ the worker if it receives too many errors with the ``--failure-limit `` option of
505+ the ``messenger:consume `` command.
506+
500507**Restart Workers on Deploy **
501508 Each time you deploy, you'll need to restart all your worker processes so
502509 that they see the newly deployed code. To do this, run ``messenger:stop-workers ``
503510 on deployment. This will signal to each worker that it should finish the message
504- it's currently handling and should shut down gracefully. Then, Supervisor will create
505- new worker processes. The command uses the :ref: `app <cache-configuration-with-frameworkbundle >`
511+ it's currently handling and should shut down gracefully. Then, the process manager
512+ will create new worker processes. The command uses the :ref: `app <cache-configuration-with-frameworkbundle >`
506513 cache internally - so make sure this is configured to use an adapter you like.
507514
508515**Use the Same Cache Between Deploys **
@@ -669,11 +676,25 @@ times:
669676 startsecs =0
670677 autostart =true
671678 autorestart =true
679+ startretries =10
672680 process_name =%(program_name)s_%(process_num)02d
673681
674682 Change the ``async `` argument to use the name of your transport (or transports)
675683and ``user `` to the Unix user on your server.
676684
685+ .. caution ::
686+
687+ During a deployment, something might be unavailable (e.g. the
688+ database) causing the consumer to fail to start. In this situation,
689+ Supervisor will try ``startretries `` number of times to restart the
690+ command. Make sure to change this setting to avoid getting the command
691+ in a FATAL state, which will never restart again.
692+
693+ Each restart, Supervisor increases the delay by 1 second. For instance, if
694+ the value is ``10 ``, it will wait 1 sec, 2 sec, 3 sec, etc. This gives the
695+ service a total of 55 seconds to become available again. Increase the
696+ ``startretries `` setting to cover the maximum expected downtime.
697+
677698If you use the Redis Transport, note that each worker needs a unique consumer
678699name to avoid the same message being handled by multiple workers. One way to
679700achieve this is to set an environment variable in the Supervisor configuration
@@ -696,7 +717,7 @@ Next, tell Supervisor to read your config and start your workers:
696717 See the `Supervisor docs `_ for more details.
697718
698719Graceful Shutdown
699- ~~~~~~~~~~~~~~~~~
720+ .................
700721
701722If you install the `PCNTL `_ PHP extension in your project, workers will handle
702723the ``SIGTERM `` POSIX signal to finish processing their current message before
@@ -712,6 +733,88 @@ of the desired grace period in seconds) in order to perform a graceful shutdown:
712733 [program:x]
713734 stopwaitsecs =20
714735
736+ .. _messenger-systemd :
737+
738+ Systemd Configuration
739+ ~~~~~~~~~~~~~~~~~~~~~
740+
741+ While Supervisor is a great tool, it has the disadvantage that you need system
742+ access to run it. Systemd has become the standard on most Linux distributions,
743+ and has a good alternative called *user services *.
744+
745+ Systemd user service configuration files typically live in a ``~/.config/systemd/user ``
746+ directory. For example, you can create a new ``messenger-worker.service `` file. Or a
747+ ``messenger-worker@.service `` file if you want more instances running at the same time:
748+
749+ .. code-block :: ini
750+
751+ [Unit]
752+ Description =Symfony messenger-consume %i
753+
754+ [Service]
755+ ExecStart =php /path/to/your/app/bin/console messenger:consume async --time-limit =3600
756+ Restart =always
757+ RestartSec =30
758+
759+ [Install]
760+ WantedBy =default.target
761+
762+ Now, tell systemd to enable and start one worker:
763+
764+ .. code-block :: terminal
765+
766+ $ systemctl --user enable messenger-worker@1.service
767+ $ systemctl --user start messenger-worker@1.service
768+
769+ # to enable and start 20 workers
770+ $ systemctl --user enable messenger-worker@{1..20}.service
771+ $ systemctl --user start messenger-worker@{1..20}.service
772+
773+ If you change your service config file, you need to reload the daemon:
774+
775+ .. code-block :: terminal
776+
777+ $ systemctl --user daemon-reload
778+
779+ To restart all your consumers:
780+
781+ .. code-block :: terminal
782+
783+ $ systemctl --user restart messenger-consume@*.service
784+
785+ The systemd user instance is only started after the first login of the
786+ particular user. Consumer often need to start on system boot instead.
787+ Enable lingering on the user to activate that behavior:
788+
789+ .. code-block :: terminal
790+
791+ $ loginctl enable-linger <your-username>
792+
793+ Logs are managed by journald and can be worked with using the journalctl
794+ command:
795+
796+ .. code-block :: terminal
797+
798+ # follow logs of consumer nr 11
799+ $ journalctl -f --user-unit messenger-consume@11.service
800+
801+ # follow logs of all consumers
802+ $ journalctl -f --user-unit messenger-consume@*
803+
804+ # follow all logs from your user services
805+ $ journalctl -f _UID=$UID
806+
807+ See the `systemd docs `_ for more details.
808+
809+ .. note ::
810+
811+ You either need elevated privileges for the ``journalctl `` command, or add
812+ your user to the systemd-journal group:
813+
814+ .. code-block :: terminal
815+
816+ $ sudo usermod -a -G systemd-journal <your-username>
817+
715818 Stateless Worker
716819~~~~~~~~~~~~~~~~
717820
@@ -2190,6 +2293,8 @@ middleware and *only* include your own:
21902293 If a middleware service is abstract, a different instance of the service will
21912294 be created per bus.
21922295
2296+ .. _middleware-doctrine :
2297+
21932298Middleware for Doctrine
21942299~~~~~~~~~~~~~~~~~~~~~~~
21952300
@@ -2377,6 +2482,7 @@ Learn more
23772482.. _`streams` : https://redis.io/topics/streams-intro
23782483.. _`Supervisor docs` : http://supervisord.org/
23792484.. _`PCNTL` : https://www.php.net/manual/book.pcntl.php
2485+ .. _`systemd docs` : https://www.freedesktop.org/wiki/Software/systemd/
23802486.. _`SymfonyCasts' message serializer tutorial` : https://symfonycasts.com/screencast/messenger/transport-serializer
23812487.. _`Long polling` : https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html
23822488.. _`Visibility Timeout` : https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html
0 commit comments