Skip to content

Commit 53f6e0a

Browse files
author
A. Jesse Jiryu Davis
committed
Rewrite "requests" doc for MongoClient and new w=1 default PYTHON-423
1 parent feaadd4 commit 53f6e0a

File tree

1 file changed

+49
-73
lines changed

1 file changed

+49
-73
lines changed

doc/examples/requests.rst

Lines changed: 49 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -3,62 +3,27 @@ Requests
33

44
PyMongo supports the idea of a *request*: a series of operations executed with
55
a single socket, which are guaranteed to be processed on the server in the same
6-
order as they ran on the client. This can be useful, for example, if you want
7-
to do a series of :meth:`~pymongo.collection.Collection.insert` or
8-
:meth:`~pymongo.collection.Collection.update` operations with ``safe=False``,
9-
and still be certain the next :meth:`~pymongo.collection.Collection.find` or
10-
:meth:`~pymongo.collection.Collection.count` is executed on the server after
11-
the inserts complete. This is called "read-your-writes consistency."
12-
(Another way to guarantee ordering is to pass ``safe=True`` to `insert` and
13-
`update`. This ensures your code will block until the write has completed, with
14-
the additional advantage that errors on the server will be reported to the
15-
client.)
16-
17-
By default, PyMongo starts a request for each thread when the thread first runs
18-
an operation on MongoDB. This guarantees read-your-writes consistency. Within a
19-
request, the thread will continue to use the same socket exclusively, and no
20-
other thread will use this socket, until the thread calls
21-
:meth:`~pymongo.connection.Connection.end_request` or it terminates. At that
22-
point, the socket is returned to the connection pool for use by other threads.
23-
24-
When to turn off auto_start_request
25-
-----------------------------------
26-
27-
If your application has many threads running simultaneously, but those threads
28-
rarely access MongoDB, you can improve performance and reduce the number of
29-
connections by creating a :class:`~pymongo.connection.Connection` with
30-
``auto_start_request=False``.
31-
32-
An example of an application that would benefit from turning off
33-
``auto_start_request`` is a web crawler that spawns many threads. Each thread
34-
fetches web pages from the Internet, analyzes them, and inserts the results
35-
into MongoDB. Since each thread will spend much more time downloading and
36-
analyzing pages than it does using its connection to MongoDB, it could use
37-
fewer connections, and thus put less load on MongoDB, if it creates a
38-
:class:`~pymongo.connection.Connection` with ``auto_start_request=False``.
39-
40-
Without ``auto_start_request`` you can still guarantee ordering, either by
41-
creating the :class:`~pymongo.connection.Connection` with ``safe=True``, or by
42-
passing ``safe=True`` to each :meth:`~pymongo.connection.Connection.insert` or
43-
:meth:`~pymongo.connection.Connection.update`, or by executing only the series
44-
of operations in which ordering is important within a request.
45-
46-
When to use start_request explicitly
47-
------------------------------------
48-
49-
If your application will benefit from turning off ``auto_start_request`` but
50-
still needs to do fire-and-forget writes, and then read the result of those
51-
writes, then you should use :meth:`~pymongo.connection.Connection.start_request`
52-
and :meth:`~pymongo.connection.Connection.end_request` around the section of
53-
code that requires this form of consistency.
54-
55-
.. testsetup::
56-
57-
from pymongo import Connection
58-
connection = Connection(auto_start_request=False)
59-
db = connection.requests_example
60-
counts = db.counts
61-
counts.drop()
6+
order as they ran on the client.
7+
8+
Requests are not usually necessary with PyMongo.
9+
By default, the methods :meth:`~pymongo.collection.Collection.insert`,
10+
:meth:`~pymongo.collection.Collection.update`, and
11+
:meth:`~pymongo.collection.Collection.remove` block until they receive
12+
acknowledgment from the server, so ordered execution is already guaranteed. You
13+
can be certain the next :meth:`~pymongo.collection.Collection.find` or
14+
:meth:`~pymongo.collection.Collection.count`, for example, is executed on the
15+
server after the writes complete. This is called "read-your-writes
16+
consistency."
17+
18+
An example of when a request is necessary is if a series of documents are
19+
inserted with ``w=0`` for performance reasons, and you want to query those
20+
documents immediately afterward: With ``w=0`` the writes can queue up at the
21+
server and might not be immediately visible in query results. Wrapping the
22+
inserts and queries within
23+
:meth:`~pymongo.mongo_client.MongoClient.start_request` and
24+
:meth:`~pymongo.mongo_client.MongoClient.end_request` forces a query to be on
25+
the same socket as the inserts, so the query won't execute until the inserts
26+
are complete on the server side.
6227

6328
Example
6429
-------
@@ -68,30 +33,41 @@ number of page views our site has served for each combination of browser,
6833
region, and OS, and then show the user the number of page views from his or her
6934
region, *including* the user's own visit. We have three ways to do so reliably:
7035

71-
1. Simply update the counters with ``safe=True``, and then ``find`` all
72-
counters for the visitor's region. This will ensure that the `update` completes
73-
before the `find` begins, but it comes with a performance penalty that may be
74-
unacceptable for analytics.
36+
1. Simply update the counters with an acknowledged write (the default), and
37+
then ``find`` all counters for the visitor's region. This will ensure that the
38+
``update`` completes before the ``find`` begins, but it comes with a performance
39+
penalty that may be unacceptable for analytics.
40+
41+
2. Create the :class:`~pymongo.mongo_client.MongoClient` with ``w=0`` and
42+
``auto_start_request=True`` to do unacknowledged writes and ensure each thread
43+
gets its own socket.
7544

76-
2. Create the :class:`~pymongo.connection.Connection` with
77-
``auto_start_request=True`` to ensure each thread gets its own socket.
45+
3. Explicitly call :meth:`~pymongo.mongo_client.MongoClient.start_request`,
46+
then do the unacknowledged updates and the queries within the request. This
47+
third method looks like:
7848

79-
3. Create the :class:`~pymongo.connection.Connection` with
80-
``auto_start_request=False`` and explicitly call
81-
:meth:`~pymongo.connection.Connection.start_request` before executing the
82-
updates and queries. This third method looks like this:
49+
.. testsetup::
50+
51+
from pymongo import MongoClient
52+
client = MongoClient()
53+
counts = client.requests_example.counts
54+
counts.drop()
55+
region, browser, os = 'US', 'Firefox', 'Mac OS X'
8356

8457
.. doctest::
8558

59+
>>> client = MongoClient()
60+
>>> counts = client.requests_example.counts
8661
>>> region, browser, os = 'US', 'Firefox', 'Mac OS X'
87-
>>> request = connection.start_request()
62+
>>> request = client.start_request()
8863
>>> try:
8964
... counts.update(
9065
... {'region': region, 'browser': browser, 'os': os},
9166
... {'$inc': {'n': 1 }},
9267
... upsert=True,
93-
... safe=False) # fire-and-forget write
94-
... # always runs after update has completed
68+
... w=0) # unacknowledged write
69+
...
70+
... # This always runs after update has completed:
9571
... count = sum([p['n'] for p in counts.find({'region': region})])
9672
... finally:
9773
... request.end()
@@ -104,16 +80,16 @@ the previous example more terse:
10480

10581
.. doctest::
10682

107-
>>> connection.in_request()
83+
>>> client.in_request()
10884
False
109-
>>> with connection.start_request():
110-
... # connection is now in request
85+
>>> with client.start_request():
86+
... # MongoClient is now in request
11187
... counts.update(
11288
... {'region': region, 'browser': browser, 'os': os},
11389
... {'$inc': {'n': 1 }},
11490
... upsert=True,
11591
... safe=False)
11692
... print sum([p['n'] for p in counts.find({'region': region})])
11793
2
118-
>>> connection.in_request() # request automatically ended
94+
>>> client.in_request() # request automatically ended
11995
False

0 commit comments

Comments
 (0)