Skip to content

Commit dc42fe8

Browse files
RUBY-3434: Improve documentation for forking servers (#2856)
* Clarify documentation for forking servers * Tweaks * More tweaks * Correct method name
1 parent dd1adad commit dc42fe8

File tree

2 files changed

+57
-76
lines changed

2 files changed

+57
-76
lines changed

Diff for: docs/reference/create-client.txt

+55-74
Original file line numberDiff line numberDiff line change
@@ -1641,102 +1641,83 @@ Usage with Forking Servers
16411641

16421642
.. note::
16431643

1644-
Applications using Mongoid should follow `Mongoid's forking guidance
1645-
<https://mongodb.com/docs/mongoid/current/tutorials/mongoid-configuration/#usage-with-forking-servers>`_.
1646-
The guidance and sample code below is provided for applications using the
1647-
Ruby driver directly.
1644+
Applications using Mongoid should follow `Mongoid's "Usage with Forking Servers" documentation
1645+
<https://www.mongodb.com/docs/mongoid/current/reference/configuration/#usage-with-forking-servers>`_.
1646+
The guidance below is provided for applications using the Ruby driver directly.
16481647

16491648
When using the Mongo Ruby driver in a Web application with a forking web server
1650-
such as Unicorn, Puma or Passenger, or when the application otherwise forks,
1651-
each process should generally each have their own ``Mongo::Client`` instances.
1652-
This is because:
1653-
1654-
1. The background threads remain in the parent process and are not transferred
1655-
to the child process.
1656-
2. File descriptors like network sockets are shared between parent and
1657-
child processes.
1658-
1659-
The driver attempts to detect client use from forked processes and
1660-
reestablish network connections when such use is detected, alleviating
1661-
the issue of file descriptor sharing.
1662-
1663-
If both parent and child processes need to perform MongoDB operations,
1664-
it is recommended for each of the processes to create their own
1665-
``Mongo::Client`` instances. Specifically, the child process should create
1666-
its own client instance and not use any of the instances that were created
1667-
in the parent.
1668-
1669-
If the parent continues to perform MongoDB operations using an already
1670-
established client instance after forking children, this client instance will
1671-
continue to operate normally as long as no child uses it in any way.
1672-
The child processes will not inherit any of the monitoring threads, and
1673-
will not perform background operations on the client instance.
1674-
1675-
If the parent does not need to perform MongoDB operation after forking
1676-
children (which is what typically happens in web applications), the parent
1677-
should close all of the client instances it created to free up connections
1678-
and cease background monitoring:
1649+
such as Puma, or when the application otherwise forks, each process (parent and child)
1650+
must have its own client connections. This is because:
1651+
1652+
1. Background Ruby threads, such as those used by the Ruby MongoDB driver to
1653+
monitor connection state, are **not** transferred to the child process.
1654+
2. File descriptors like network sockets **are** shared between parent and
1655+
child processes, which can cause I/O conflicts.
1656+
1657+
Regarding (1), if you do not restart the driver's monitoring threads
1658+
on the child process after forking, although your child may initially
1659+
appear to function correctly, you will eventually see
1660+
``Mongo::Error::NoServerAvailable`` exceptions if/when your MongoDB cluster
1661+
state changes, for example due to network errors or a maintenance event.
1662+
1663+
Regarding (2), if a child process reuses the parent's file descriptors, you
1664+
will see ``Mongo::Error::SocketError`` errors with messages such as
1665+
``Errno::EPIPE: Broken pipe`` and ``EOFError: end of file reached``.
1666+
1667+
When the Ruby driver is used in a web application, if possible,
1668+
we recommend to not create any ``Mongo::Client`` instances in the parent
1669+
process (prior to the workers being forked), and instead only create client
1670+
instances in the workers.
1671+
1672+
Manually Handling Process Forks
1673+
-------------------------------
1674+
1675+
Certain advanced use cases, such as `Puma's fork_worker option <https://github.com/puma/puma/blob/master/docs/fork_worker.md>`_,
1676+
require ``Mongo::Client`` instances to be open in both the parent
1677+
and child processes. In this case, you must handle client
1678+
reconnection manually.
1679+
1680+
To do this, immediately before forking, close any existing client connections
1681+
on your parent process. This will prevent the parent process from experiencing
1682+
network and monitoring errors due to the child's reuse of the parent's
1683+
file descriptors.
16791684

16801685
.. code-block:: ruby
16811686

1682-
client.reconnect
1687+
# Immediately before fork
1688+
client.close
16831689

16841690
.. note::
16851691

1686-
If the parent process performs operations on the Mongo client and does not
1687-
close it, the parent process will continue consuming a connection slot
1688-
in the cluster and will continue monitoring the cluster for as long as the
1689-
parent remains alive.
1690-
1691-
Reconnecting Client Instances
1692-
-----------------------------
1692+
Calling ``Client#close`` does not disrupt database operations currently in-flight.
1693+
Clients will automatically reconnect when you perform new operations.
16931694

1694-
When the Ruby driver is used in a web application, it is recommended to not
1695-
create any ``Mongo::Client`` instances in the management processes (prior to
1696-
the workers being forked), and instead only create client instances in the
1697-
workers.
1698-
1699-
It is possible, although not recommended, to use the same ``Mongo::Client``
1700-
instances in parent and child processes. In order to do so, the instance
1701-
must be closed and reconnected in the child process so that the background
1702-
threads can be recreated:
1695+
Then, immediately after forking, reconnect your clients in the newly
1696+
forked child process, which will respawn the driver's monitoring threads.
17031697

17041698
.. code-block:: ruby
17051699

1706-
client.close
1700+
# Immediately after fork
17071701
client.reconnect
17081702

1709-
.. note::
1710-
1711-
This pattern should be used with Ruby driver version 2.6.2 or higher.
1712-
Previous driver versions did not recreate monitoring threads when
1713-
reconnecting.
1714-
1715-
.. note::
1716-
1717-
When closing and reconnecting the client instance in the child,
1718-
due to file descriptor sharing, the parent process may experience network
1719-
and monitoring errors.
1720-
1721-
Web servers generally provide hooks that can be used by applications to
1722-
perform actions when the worker processes are forked. The recommended hooks
1723-
to use are:
1703+
Most web servers provide hooks that can be used by applications to
1704+
perform actions when the worker processes are forked. The recommended
1705+
hooks are:
17241706

1725-
- For `Puma <https://puma.io/puma/>`_, ``before_fork`` to close clients in the
1726-
parent process and ``on_worker_boot`` to reconnect in the child processes.
1707+
- For `Puma <https://puma.io/puma/#clustered-mode>`_,
1708+
use ``before_fork`` and ``on_refork`` to close clients in
1709+
the parent process and ``on_worker_boot`` to reconnect in the
1710+
child processes.
17271711
- For `Unicorn <https://yhbt.net/unicorn/Unicorn/Configurator.html>`_,
17281712
``before_fork`` to close clients in the parent process and
17291713
``after_fork`` to reconnect clients in the child processes.
17301714
- For `Passenger <https://www.phusionpassenger.com/library/indepth/ruby/spawn_methods/#unintentional-file-descriptor-sharing>`_,
17311715
``starting_worker_process`` to reconnect clients in the child processes
17321716
(Passenger does not appear to have a pre-fork hook).
17331717

1734-
This documentation does not provide example code for using the aforementioned
1735-
hooks, because there is no standard for client instance management when
1736-
using the Ruby driver directly. `Mongoid documentation
1737-
<https://mongodb.com/docs/mongoid/current/tutorials/mongoid-configuration/#usage-with-forking-servers>`_
1738-
however provides examples for closing clients in the parent process and
1739-
reconnecting clients in the child processes.
1718+
Refer to `Mongoid's "Usage with Forking Servers" documentation
1719+
<https://www.mongodb.com/docs/mongoid/current/reference/configuration/#usage-with-forking-servers>`_
1720+
for further examples.
17401721

17411722
Troubleshooting
17421723
---------------

Diff for: lib/mongo/config.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ module Config
1616

1717
# When this flag is off, an aggregation done on a view will be executed over
1818
# the documents included in that view, instead of all documents in the
19-
# collection. When this flag is on, the view fiter is ignored.
19+
# collection. When this flag is on, the view filter is ignored.
2020
option :broken_view_aggregate, default: true
2121

2222
# When this flag is set to false, the view options will be correctly
2323
# propagated to readable methods.
2424
option :broken_view_options, default: true
2525

2626
# When this flag is set to true, the update and replace methods will
27-
# validate the paramters and raise an error if they are invalid.
27+
# validate the parameters and raise an error if they are invalid.
2828
option :validate_update_replace, default: false
2929

3030
# Set the configuration options.

0 commit comments

Comments
 (0)