Skip to content

Commit c486cdb

Browse files
committed
Messenger process managers
Add information about mysql timeouts, supervisor FATAL, systemd user services. Add docs for #13617
1 parent 5514b60 commit c486cdb

File tree

1 file changed

+142
-4
lines changed

1 file changed

+142
-4
lines changed

messenger.rst

+142-4
Original file line numberDiff line numberDiff line change
@@ -462,22 +462,29 @@ Deploying to Production
462462

463463
On production, there are a few important things to think about:
464464

465-
**Use Supervisor to keep your worker(s) running**
465+
**Use a process manager like Supervisor or systemd to keep your worker(s) running**
466466
You'll want one or more "workers" running at all times. To do that, use a
467-
process control system like :ref:`Supervisor <messenger-supervisor>`.
467+
process control system like :ref:`Supervisor <messenger-supervisor>`
468+
or :ref:`systemd <messenger-systemd>`.
468469

469470
**Don't Let Workers Run Forever**
470471
Some services (like Doctrine's EntityManager) will consume more memory
471472
over time. So, instead of allowing your worker to run forever, use a flag
472473
like ``messenger:consume --limit=10`` to tell your worker to only handle 10
473-
messages before exiting (then Supervisor will create a new process). There
474+
messages before exiting (then the process manager will create a new process). There
474475
are also other options like ``--memory-limit=128M`` and ``--time-limit=3600``.
475476

477+
**Stopping Workers That Encounter Errors**
478+
If a worker dependency like your database server is down, or timeout is reached,
479+
you can try to add :ref:`reconnect logic <middleware-doctrine>`, or just quit
480+
the worker if it receives too many errors with the ``--failure-limit`` option of
481+
the ``messenger:consume`` command.
482+
476483
**Restart Workers on Deploy**
477484
Each time you deploy, you'll need to restart all your worker processes so
478485
that they see the newly deployed code. To do this, run ``messenger:stop-workers``
479486
on deploy. This will signal to each worker that it should finish the message
480-
it's currently handling and shut down gracefully. Then, Supervisor will create
487+
it's currently handling and shut down gracefully. Then, the process manager will create
481488
new worker processes. The command uses the :ref:`app <cache-configuration-with-frameworkbundle>`
482489
cache internally - so make sure this is configured to use an adapter you like.
483490

@@ -633,6 +640,134 @@ config and start your workers:
633640
634641
See the `Supervisor docs`_ for more details.
635642

643+
It is possible to end up in a situation where the supervisor job gets into a
644+
FATAL (too many start retries) state when trying to restart when something is
645+
not yet available. You can prevent this by wrapping the Symfony script with a
646+
shell script and sleep when the script fails:
647+
648+
.. code-block:: bash
649+
650+
#!/usr/bin/env bash
651+
652+
# Supervisor sends TERM to services when stopped.
653+
# This wrapper has to pass the signal to it's child.
654+
# Note that we send TERM (graceful) instead of KILL (immediate).
655+
_term() {
656+
echo "[GOT TERM, SIGNALING CHILD]"
657+
kill -TERM "$child" 2>/dev/null
658+
exit 1
659+
}
660+
661+
trap _term SIGTERM
662+
663+
# Execute console.php with whatever arguments were specified to this script
664+
"$@" &
665+
child=$!
666+
wait "$child"
667+
rc=$?
668+
669+
# Delay to prevent supervisor from restarting too fast on failure
670+
sleep 30
671+
672+
# Return with the exit code of the wrapped process
673+
exit $rc
674+
675+
The supervisor job would then look like this:
676+
677+
.. code-block:: ini
678+
679+
;/etc/supervisor/conf.d/messenger-worker.conf
680+
[program:messenger-consume]
681+
command=/path/to/your/app/bin/console_wrapper php /path/to/your/app/bin/console messenger:consume async --time-limit=3600"
682+
...
683+
684+
.. _messenger-systemd:
685+
686+
Systemd Configuration
687+
~~~~~~~~~~~~~~~~~~~~~
688+
689+
While Supervisor is a great tool, it has the disadvantage that you need system
690+
access to run it. Systemd has become the standard on most Linux distributions,
691+
and has a good alternative called user services.
692+
693+
Systemd user service configuration files typically live in a ``~/.config/systemd/user``
694+
directory. For example, you can create a new ``messenger-worker.service`` file. Or a
695+
``[email protected]`` file if you want more instances running at the same time:
696+
697+
.. code-block:: ini
698+
699+
[Unit]
700+
Description=Symfony messenger-consume %i
701+
702+
[Service]
703+
ExecStart=php /path/to/your/app/bin/console messenger:consume async --time-limit=3600
704+
Restart=always
705+
RestartSec=30
706+
707+
[Journal]
708+
Storage=persistent
709+
710+
[Install]
711+
WantedBy=default.target
712+
713+
Now, tell systemd to enable and start one worker:
714+
715+
.. code-block:: terminal
716+
717+
$ systemctl --user enable [email protected]
718+
719+
$ systemctl --user start [email protected]
720+
721+
Then enable and start another 19:
722+
723+
.. code-block:: terminal
724+
725+
$ systemctl --user enable messenger-worker@{2..20}.service
726+
727+
$ systemctl --user start messenger-worker@{2..20}.service
728+
729+
If you would change your service config file, reload the daemon:
730+
731+
.. code-block:: terminal
732+
733+
$ systemctl --user daemon-reload
734+
735+
Restart all your consumers:
736+
737+
.. code-block:: terminal
738+
739+
$ systemctl --user restart messenger-consume@*.service
740+
741+
The systemd user instance is only started after the first login of the
742+
particular user. We want to start our workers on system boot instead. Enable
743+
lingering on the user to activate that behavior:
744+
745+
.. code-block:: terminal
746+
747+
$ loginctl enable-linger <your-username>
748+
749+
Logs are managed by journald and can be worked with using the journalctl
750+
command, but you do need elevated privileges for that, or add your user to the
751+
systemd-journal group:
752+
753+
.. code-block:: terminal
754+
755+
$ sudo usermod -a -G systemd-journal <your-username>
756+
757+
Now you can watch your service logs as your user, for example tail and follow
758+
the logs of [email protected], all messenger-consume services, or
759+
tail and follow all logs for your user ID:
760+
761+
.. code-block:: terminal
762+
763+
$ journalctl -f --user-unit [email protected]
764+
765+
$ journalctl -f --user-unit messenger-consume@*
766+
767+
$ journalctl -f _UID=$UID
768+
769+
See the `systemd docs`_ for more details.
770+
636771
.. _messenger-retries-failures:
637772

638773
Retries & Failures
@@ -1541,6 +1676,8 @@ middleware and *only* include your own:
15411676
If a middleware service is abstract, a different instance of the service will
15421677
be created per bus.
15431678

1679+
.. _middleware-doctrine:
1680+
15441681
Middleware for Doctrine
15451682
~~~~~~~~~~~~~~~~~~~~~~~
15461683

@@ -1663,4 +1800,5 @@ Learn more
16631800
.. _`Enqueue's transport`: https://github.com/sroze/messenger-enqueue-transport
16641801
.. _`streams`: https://redis.io/topics/streams-intro
16651802
.. _`Supervisor docs`: http://supervisord.org/
1803+
.. _`systemd docs`: https://www.freedesktop.org/wiki/Software/systemd/
16661804
.. _`SymfonyCasts' message serializer tutorial`: https://symfonycasts.com/screencast/messenger/transport-serializer

0 commit comments

Comments
 (0)