@@ -863,58 +863,57 @@ as the following example shows:
863863Usage with Forking Servers
864864==========================
865865
866- When using Mongoid with a forking web server such as Puma, Unicorn or
867- Passenger, it is recommended to not perform any operations on Mongoid models
868- in the parent process prior to the fork.
869-
870- When a process forks, Ruby threads are not transferred to the child processes
871- and the Ruby driver Client objects lose their background monitoring. The
872- application will typically seem to work just fine until the deployment
873- state changes (for example due to network errors, a maintenance event) at
874- which point the application is likely to start getting ``NoServerAvailable``
875- exception when performing MongoDB operations.
876-
877- If the parent process needs to perform operations on the MongoDB database,
878- reset all clients in the workers after they forked. How to do so depends
879- on the web server being used.
880-
881- If the parent process does not need to perform operations on the MongoDB
882- database after child processes are forked, close the clients in the parent
883- prior to forking children. If the parent process performs operations on a Mongo
884- client and does not close it, the parent process will continue consuming a
885- connection slot in the cluster and will continue monitoring the cluster for
886- as long as the parent remains alive.
887-
888- .. note::
889-
890- The close/reconnect pattern described here should be used with Ruby driver
891- version 2.6.2 or higher. Previous driver versions did not recreate
892- monitoring threads when reconnecting.
866+ When using Mongoid with a forking web server such as Puma, or any application
867+ that otherwise forks to spawn child processes, special considerations apply.
868+
869+ If possible, we recommend to not perform any MongoDB operations in the parent
870+ process prior to forking, which will avoid any forking-related pitfalls.
871+
872+ A detailed technical explanation of how the Mongo Ruby Driver handles forking
873+ is given in the `driver's "Usage with Forking Servers" documentation
874+ <https://www.mongodb.com/docs/ruby-driver/current/reference/create-client/#usage-with-forking-servers>`.
875+ In a nutshell, to avoid various connection errors such as ``Mongo::Error::SocketError``
876+ and ``Mongo::Error::NoServerAvailable``, you must do the following:
877+
878+ 1. Disconnect MongoDB clients in the parent Ruby process immediately *before*
879+ forking using ``Mongoid.disconnect_clients``. This ensures the parent and child
880+ process do not accidentally reuse the same sockets and have I/O conflicts.
881+ Note that ``Mongoid.disconnect_clients`` does not disrupt any in-flight
882+ MongoDB operations, and will automatically reconnect when you perform new
883+ operations.
884+ 2. Reconnect your MongoDB clients in the child Ruby process immediately *after*
885+ forking using ``Mongoid.reconnect_clients``. This is required to respawn
886+ the driver's monitoring threads in the child process.
887+
888+ Most web servers provide hooks that can be used by applications to
889+ perform actions when the worker processes are forked. The following
890+ are configuration examples for several common Ruby web servers.
893891
894892Puma
895893----
896894
897895Use the ``on_worker_boot`` hook to reconnect clients in the workers and
898- the ``before_fork`` hook to close clients in the parent process
899- (`Puma documentation <https://puma.io/puma/>`_):
896+ the ``before_fork`` and ``on_refork`` hooks to close clients in the
897+ parent process (`Puma documentation <https://puma.io/puma/#clustered-mode >`_).
900898
901899.. code-block:: ruby
902900
903- on_worker_boot do
904- if defined?(Mongoid)
905- Mongoid::Clients.clients.each do |name, client|
906- client.close
907- client.reconnect
908- end
909- else
910- raise "Mongoid is not loaded. You may have forgotten to enable app preloading."
911- end
912- end
901+ # config/puma.rb
913902
903+ # Runs in the Puma master process before it forks a child worker.
914904 before_fork do
915- if defined?(Mongoid)
916- Mongoid.disconnect_clients
917- end
905+ Mongoid.disconnect_clients
906+ end
907+
908+ # Required when using Puma's fork_worker option. Runs in the
909+ # child worker 0 process before it forks grandchild workers.
910+ on_refork do
911+ Mongoid.disconnect_clients
912+ end
913+
914+ # Runs in each Puma child process after it forks from its parent.
915+ on_worker_boot do
916+ Mongoid.reconnect_clients
918917 end
919918
920919Unicorn
@@ -926,21 +925,14 @@ the ``before_fork`` hook to close clients in the parent process
926925
927926.. code-block:: ruby
928927
929- after_fork do |server, worker|
930- if defined?(Mongoid)
931- Mongoid::Clients.clients.each do |name, client|
932- client.close
933- client.reconnect
934- end
935- else
936- raise "Mongoid is not loaded. You may have forgotten to enable app preloading."
937- end
928+ # config/unicorn.rb
929+
930+ before_fork do |_server, _worker|
931+ Mongoid.disconnect_clients
938932 end
939933
940- before_fork do |server, worker|
941- if defined?(Mongoid)
942- Mongoid.disconnect_clients
943- end
934+ after_fork do |_server, _worker|
935+ Mongoid.reconnect_clients
944936 end
945937
946938Passenger
@@ -956,12 +948,7 @@ before the workers are forked.
956948
957949 if defined?(PhusionPassenger)
958950 PhusionPassenger.on_event(:starting_worker_process) do |forked|
959- if forked
960- Mongoid::Clients.clients.each do |name, client|
961- client.close
962- client.reconnect
963- end
964- end
951+ Mongoid.reconnect_clients if forked
965952 end
966953 end
967954
0 commit comments