@@ -863,58 +863,57 @@ as the following example shows:
863
863
Usage with Forking Servers
864
864
==========================
865
865
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.
893
891
894
892
Puma
895
893
----
896
894
897
895
Use 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 >`_).
900
898
901
899
.. code-block:: ruby
902
900
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
913
902
903
+ # Runs in the Puma master process before it forks a child worker.
914
904
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
918
917
end
919
918
920
919
Unicorn
@@ -926,21 +925,14 @@ the ``before_fork`` hook to close clients in the parent process
926
925
927
926
.. code-block:: ruby
928
927
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
938
932
end
939
933
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
944
936
end
945
937
946
938
Passenger
@@ -956,12 +948,7 @@ before the workers are forked.
956
948
957
949
if defined?(PhusionPassenger)
958
950
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
965
952
end
966
953
end
967
954
0 commit comments