限制MongoDB Server执行时间
在此页面上
Overview
当您使用 PyMongo 执行服务器操作时,您还可以限制服务器完成此操作的时间。 为此,请指定客户端操作超时时间。 超时适用于完成操作所需的所有步骤,包括服务器选择、连接签出、序列化和服务器端执行。 超时后,PyMongo 会引发超时异常。
您可以通过两种方式指定超时:使用 timeout()
方法或使用timeoutMS
连接选项。
timeout() 方法
要在代码中指定超时,请调用timeout()
方法并向其传递超时长度(以秒为单位)。 您必须在with
语句中调用timeout()
方法,如以下示例所示:
with pymongo.timeout(10): collection.insert_one({"name": "Yngwie"})
在前面的示例中,如果插入操作没有在10秒内完成,PyMongo 将引发错误。
您指定的超时适用于with
区块内的所有操作。 在以下示例中,插入和查找操作都必须在总共10秒内完成:
with pymongo.timeout(10): coll.insert_one({"name": "Yngwie"}) coll.find_one({"name": "Yngwie"})
嵌套超时区块
当执行进入嵌套超时区块时,外部超时将暂停。 当执行退出嵌套超时块时,将恢复之前的超时。
重要
嵌套超时块可以缩短外部超时块的截止时间,但不能延长它。
以下示例展示了如何使用对timeout()
方法的嵌套调用:
1 with pymongo.timeout(5): 2 collection.find_one() 3 with pymongo.timeout(3): 4 collection.find_one() 5 collection.find_one() 6 with pymongo.timeout(10): 7 collection.find_one() 8 collection.find_one()
在前面的示例中,代码执行以下步骤:
第1行:创建一个五秒的超时区块。
- 第2行:在五秒超时区块内调用
find_one()
方法。 服务器必须 - 在五秒超时内完成此操作。
- 第2行:在五秒超时区块内调用
第3行:创建一个嵌套的三秒超时块。
- 第4行:在三秒超时区块内调用
find_one()
方法。 服务器必须 - 在三秒内完成此操作。
- 第4行:在三秒超时区块内调用
- 第5行:在三秒超时区块之外调用
find_one()
方法。 服务器必须 - 在原来的五秒超时内完成此操作。
- 第5行:在三秒超时区块之外调用
第6行:创建一个嵌套的 10 秒超时区块。
- 第7行:在 10 秒超时区块内调用
find_one()
方法。 嵌套超时 - 块无法扩展外部超时块,因此服务器必须在原始的五秒超时内完成此操作。
- 第7行:在 10 秒超时区块内调用
第8行:在 10 秒超时区块之外调用
find_one()
方法。 服务器必须在原来的五秒超时内完成此操作。
线程和任务安全
timeout()
方法是线程安全的。 该超时仅适用于当前线程,多个线程可以并行配置不同的超时。
timeout()
方法也是asyncio
安全的。 超时仅适用于当前任务,多个任务可以同时配置不同的超时。
以下示例展示了如何将timeout()
方法与 Motor (用于异步应用程序的MongoDB Python驾驶员程序)结合使用:
import motor.motor_asyncio client = motor.motor_asyncio.AsyncIOMotorClient() coll = client["test-db"]["test-collection"] with pymongo.timeout(10): await coll.insert_one({"name": "Yngwie"}) await coll.find_one({"name": "Yngwie"})
timeoutMS 连接选项
要在连接到 MongoDB 部署时指定超时,请将timeoutMS
连接选项设置为超时长度(以毫秒为单位)。 您可以通过两种方式执行此操作:将参数传递给 MongoClient
构造函数,或通过连接string中的参数。
以下代码示例使用timeoutMS
选项指定10秒的超时:
client = pymongo.MongoClient("mongodb://<db_username>:<db_password>@<hostname:<port>", timeoutMS=10000)
uri = "mongodb://<db_username>:<db_password>@<hostname:<port>/?timeoutMS=10000" client = pymongo.MongoClient(uri)
如果指定timeoutMS
选项,PyMongo 会自动将指定的超时应用于每个服务器操作。 以下代码示例指定10秒的超时,然后调用insert_one()
和find_one()
方法。 要查看使用timeoutMS
选项与使用timeout()
方法的对比效果,请选择相应的标签页。
uri = "mongodb://<db_username>:<db_password>@<hostname@:<port>/?timeoutMS=10000" client = pymongo.MongoClient(uri) coll = client["test-db"]["test-collection"] coll.insert_one({"name": "Yngwie"}) # Uses a 10-second timeout. coll.find_one({"name": "Yngwie"}) # Also uses a 10-second timeout.
client = MongoClient() coll = client["test-db"]["test-collection"] with pymongo.timeout(10): coll.insert_one({"name": "Yngwie"}) with pymongo.timeout(10): coll.find_one({"name": "Yngwie"})
重要
timeout() 覆盖 timeoutMS
如果您指定timeoutMS
选项,然后在代码中调用timeout()
方法,PyMongo 将忽略timeout
块内的timeoutMS
值:
client = MongoClient("mongodb://localhost/?timeoutMS=10000") coll = client["test-db"]["test-collection"] coll.insert_one({"name": "Yngwie"}) # Uses the client's 10-second timeout # pymongo.timeout overrides the client's timeoutMS. with pymongo.timeout(20): coll.insert_one({"name": "Yngwie"}) # Uses the 20-second timeout with pymongo.timeout(5): coll.find_one({"name": "Yngwie"}) # Uses the 5-second timeout
处理异常
当服务器操作超过指定超时时,PyMongo 会引发超时异常,并将PyMongoError.timeout
属性设置为True
。
以下代码示例展示了处理超时异常的一种方法。 在except
区块内,代码会检查timeout
属性,以确定异常是否由超时引起。
try: with pymongo.timeout(10): coll.insert_one({"name": "Yngwie"}) time.sleep(10) # The deadline has now expired. The next operation will raise # a timeout exception. coll.find_one({"name": "Yngwie"}) except PyMongoError as exc: if exc.timeout: print(f"block timed out: {exc!r}") else: print(f"failed with non-timeout error: {exc!r}")
故障排除
以下部分描述了使用超时时可能遇到的错误。
ServerSelectionTimeoutError
此错误表明客户端在给定超时时间内找不到可用的服务器来运行操作:
pymongo.errors.ServerSelectionTimeoutError: No servers found yet, Timeout: -0.00202266700216569s, Topology Description: <TopologyDescription id: 63698e87cebfd22ab1bd2ae0, topology_type: Unknown, servers: [<ServerDescription ('localhost', 27017) server_type: Unknown, rtt: None>]>
NetworkTimeout
此错误表示客户端无法在给定超时时间内建立连接,或者操作已发送但服务器未及时响应:
pymongo.errors.NetworkTimeout: localhost:27017: timed out
ExecutionTimeout
此错误可能表示服务器取消了操作,因为超过了给定的超时时间。 即使 PyMongo 引发此异常,该操作也可能已在服务器上部分完成。
pymongo.errors.ExecutionTimeout: operation exceeded time limit, full error: {'ok': 0.0, 'errmsg': 'operation exceeded time limit', 'code': 50, 'codeName': 'MaxTimeMSExpired'}
它还可能表明客户端取消了操作,因为无法在给定超时时间内完成操作:
pymongo.errors.ExecutionTimeout: operation would exceed time limit, remaining timeout:0.00196 <= network round trip time:0.00427
WTimeoutError
此错误表示服务器无法在给定超时内并在指定的写关注之后完成请求的写入操作:
pymongo.errors.WTimeoutError: operation exceeded time limit, full error: {'code': 50, 'codeName': 'MaxTimeMSExpired', 'errmsg': 'operation exceeded time limit', 'errInfo': {'writeConcern': {'w': 1, 'wtimeout': 0}}}
BulkWriteError
此错误表示服务器无法在给定超时内并在指定的写关注之后完成insert_many()
或bulk_write()
方法:
pymongo.errors.BulkWriteError: batch op errors occurred, full error: {'writeErrors': [], 'writeConcernErrors': [{'code': 50, 'codeName': 'MaxTimeMSExpired', 'errmsg': 'operation exceeded time limit', 'errInfo': {'writeConcern': {'w': 1, 'wtimeout': 0}}}], 'nInserted': 2, 'nUpserted': 0, 'nMatched': 0, 'nModified': 0, 'nRemoved': 0, 'upserted': []}
API 文档
要了解有关在 PyMongo 中使用超时的更多信息,请参阅以下 API 文档: