MongoDB Server実行時間の制限
項目一覧
Overview
PyMongo を使用してサーバー操作を実行する場合、サーバーがこの操作を完了するのにかかる時間を制限することもできます。 そのためには、クライアント側の 操作タイムアウトを指定します。 タイムアウトは、サーバー選択、接続チェックアウト、直列化、サーバー側実行など、操作を完了するために必要なすべてのステップを適用します。 タイムアウトが経過すると、PyMongo はタイムアウトの例外を発生させます。
タイムアウトを指定するには、 timeout()
メソッドを使用する方法と、 timeoutMS
接続オプションを使用する方法の 2 つがあります。
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()
前の例では、コードは次の手順を実行しています。
Line 1 : 5 秒のタイムアウト ブロックを作成します。
- 2行: 5 秒のタイムアウト ブロック内で
find_one()
メソッドを呼び出します。 サーバーは - この操作は 5 秒のタイムアウト以内に完了してください。
- 2行: 5 秒のタイムアウト ブロック内で
Line 3 : ネストされた 3 秒のタイムアウト ブロックを作成します。
- 4行: 3 秒のタイムアウト ブロック内で
find_one()
メソッドを呼び出します。 サーバーは - この操作は 3 秒以内に完了します。
- 4行: 3 秒のタイムアウト ブロック内で
- 5行: 3 秒のタイムアウト ブロック外で
find_one()
メソッドを呼び出します。 サーバーは - この操作を元の 5 秒のタイムアウト内に完了します。
- 5行: 3 秒のタイムアウト ブロック外で
Line 6 : ネストされた 10 秒のタイムアウト ブロックを作成します。
- 7行: 10 秒のタイムアウト ブロック内で
find_one()
メソッドを呼び出します。 ネストされたタイムアウト - ブロックは外部タイムアウト ブロックを延長できないため、サーバーは元の 5 秒タイムアウト内にこの操作を完了する必要があります。
- 7行: 10 秒のタイムアウト ブロック内で
8行: 10 秒のタイムアウト ブロック外で
find_one()
メソッドを呼び出します。 サーバーはこの操作を元の 5 秒のタイムアウト内に完了する必要があります。
スレッドとタスクの安全性
timeout()
メソッドはスレッドセーフです。 タイムアウトは現在のスレッドにのみ適用され、複数のスレッドが並行して異なるタイムアウトを設定できます。
timeout()
メソッドはasyncio
セーフでもあります。 タイムアウトは現在のタスクにのみ適用され、複数のタスクが同時に異なるタイムアウトを設定できます。
次の例は、非同期アプリケーション用のMongoDB Pythonドライバーである Motor とともに メソッドを使用する方法を示しています。timeout()
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のパラメーターを使用する方法の 2 つがあります。
次のコード例では、 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
に設定します。
次のコード例は、タイムアウト例外を処理する方法の 1 つを示しています。 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>]>
ネットワークタイムアウト
このエラーは、クライアントが指定されたタイムアウト内に接続を確立できなかったこと、または操作が送信されたがサーバーが時間内に応答しなかったことを示しています。
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
このエラーは、サーバーが指定されたタイムアウト内に、指定された書込み保証 (write concern) に従って要求された書込み操作を完了できなかったことを示しています。
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
このエラーは、サーバーが指定されたタイムアウト内に、指定された書込み保証 (write concern) に従い、 メソッドまたは メソッドを完了できなかったことを示しています。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 ドキュメントを参照してください。