@@ -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 **
@@ -695,8 +702,49 @@ Next, tell Supervisor to read your config and start your workers:
695702
696703 See the `Supervisor docs `_ for more details.
697704
705+ It is possible to end up in a situation where the supervisor job gets into a
706+ FATAL (too many start retries) state when trying to restart when something is
707+ not yet available. You can prevent this by wrapping the Symfony script with a
708+ shell script and sleep when the script fails:
709+
710+ .. code-block :: bash
711+
712+ #! /usr/bin/env bash
713+
714+ # Supervisor sends TERM to services when stopped.
715+ # This wrapper has to pass the signal to it's child.
716+ # Note that we send TERM (graceful) instead of KILL (immediate).
717+ _term () {
718+ echo " [GOT TERM, SIGNALING CHILD]"
719+ kill -TERM " $child " 2> /dev/null
720+ exit 1
721+ }
722+
723+ trap _term SIGTERM
724+
725+ # Execute console.php with whatever arguments were specified to this script
726+ " $@ " &
727+ child=$!
728+ wait " $child "
729+ rc=$?
730+
731+ # Delay to prevent supervisor from restarting too fast on failure
732+ sleep 30
733+
734+ # Return with the exit code of the wrapped process
735+ exit $rc
736+
737+ The supervisor job would then look like this:
738+
739+ .. code-block :: ini
740+
741+ ; /etc/supervisor/conf.d/messenger-worker.conf
742+ [program:messenger-consume]
743+ command =/path/to/your/app/bin/console_wrapper php /path/to/your/app/bin/console messenger:consume async --time-limit =3600"
744+ ...
745+
698746 Graceful Shutdown
699- ~~~~~~~~~~~~~~~~~
747+ .................
700748
701749If you install the `PCNTL `_ PHP extension in your project, workers will handle
702750the ``SIGTERM `` POSIX signal to finish processing their current message before
@@ -712,6 +760,88 @@ of the desired grace period in seconds) in order to perform a graceful shutdown:
712760 [program:x]
713761 stopwaitsecs =20
714762
763+ .. _messenger-systemd :
764+
765+ Systemd Configuration
766+ ~~~~~~~~~~~~~~~~~~~~~
767+
768+ While Supervisor is a great tool, it has the disadvantage that you need system
769+ access to run it. Systemd has become the standard on most Linux distributions,
770+ and has a good alternative called *user services *.
771+
772+ Systemd user service configuration files typically live in a ``~/.config/systemd/user ``
773+ directory. For example, you can create a new ``messenger-worker.service `` file. Or a
774+ ``messenger-worker@.service `` file if you want more instances running at the same time:
775+
776+ .. code-block :: ini
777+
778+ [Unit]
779+ Description =Symfony messenger-consume %i
780+
781+ [Service]
782+ ExecStart =php /path/to/your/app/bin/console messenger:consume async --time-limit =3600
783+ Restart =always
784+ RestartSec =30
785+
786+ [Install]
787+ WantedBy =default.target
788+
789+ Now, tell systemd to enable and start one worker:
790+
791+ .. code-block :: terminal
792+
793+ $ systemctl --user enable messenger-worker@1.service
794+ $ systemctl --user start messenger-worker@1.service
795+
796+ # to enable and start 20 workers
797+ $ systemctl --user enable messenger-worker@{1..20}.service
798+ $ systemctl --user start messenger-worker@{1..20}.service
799+
800+ If you change your service config file, you need to reload the daemon:
801+
802+ .. code-block :: terminal
803+
804+ $ systemctl --user daemon-reload
805+
806+ To restart all your consumers:
807+
808+ .. code-block :: terminal
809+
810+ $ systemctl --user restart messenger-consume@*.service
811+
812+ The systemd user instance is only started after the first login of the
813+ particular user. Consumer often need to start on system boot instead.
814+ Enable lingering on the user to activate that behavior:
815+
816+ .. code-block :: terminal
817+
818+ $ loginctl enable-linger <your-username>
819+
820+ Logs are managed by journald and can be worked with using the journalctl
821+ command:
822+
823+ .. code-block :: terminal
824+
825+ # follow logs of consumer nr 11
826+ $ journalctl -f --user-unit messenger-consume@11.service
827+
828+ # follow logs of all consumers
829+ $ journalctl -f --user-unit messenger-consume@*
830+
831+ # follow all logs from your user services
832+ $ journalctl -f _UID=$UID
833+
834+ See the `systemd docs `_ for more details.
835+
836+ .. note ::
837+
838+ You either need elevated privileges for the ``journalctl `` command, or add
839+ your user to the systemd-journal group:
840+
841+ .. code-block :: terminal
842+
843+ $ sudo usermod -a -G systemd-journal <your-username>
844+
715845 Stateless Worker
716846~~~~~~~~~~~~~~~~
717847
@@ -2190,6 +2320,8 @@ middleware and *only* include your own:
21902320 If a middleware service is abstract, a different instance of the service will
21912321 be created per bus.
21922322
2323+ .. _middleware-doctrine :
2324+
21932325Middleware for Doctrine
21942326~~~~~~~~~~~~~~~~~~~~~~~
21952327
@@ -2377,6 +2509,7 @@ Learn more
23772509.. _`streams` : https://redis.io/topics/streams-intro
23782510.. _`Supervisor docs` : http://supervisord.org/
23792511.. _`PCNTL` : https://www.php.net/manual/book.pcntl.php
2512+ .. _`systemd docs` : https://www.freedesktop.org/wiki/Software/systemd/
23802513.. _`SymfonyCasts' message serializer tutorial` : https://symfonycasts.com/screencast/messenger/transport-serializer
23812514.. _`Long polling` : https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html
23822515.. _`Visibility Timeout` : https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html
0 commit comments