Limitar o tempo de execução do servidor MongoDB
Nesta página
Visão geral
Ao usar o PyMongo para executar uma operação de servidor, você também pode limitar o tempo que o servidor tem para concluir a operação. Para isso, especifique um tempo limite de operação do lado do cliente. O tempo limite aplica todas as etapas necessárias para concluir a operação, incluindo seleção do servidor, verificação da conexão, serialização e execução do lado do servidor. Quando o tempo limite expira, o PyMongo gera uma exceção de tempo limite.
Você pode especificar um tempo limite de duas maneiras: usando o método timeout()
ou usando a opção de conexão timeoutMS
.
Método de timeout()
Para especificar um tempo limite em seu código, chame o método timeout()
e passe a duração do tempo limite, em segundos. Você deve chamar o método timeout()
em uma declaração with
, como mostrado no seguinte exemplo:
with pymongo.timeout(10): collection.insert_one({"name": "Yngwie"})
No exemplo anterior, se a operação de inserção não terminar dentro de 10 segundos, o PyMongo reportará um erro.
O timeout que você especifica se aplica a todas as operações dentro do bloco with
. No exemplo a seguir, as operações de inserção e localização devem terminar dentro de um total de 10 segundos:
with pymongo.timeout(10): coll.insert_one({"name": "Yngwie"}) coll.find_one({"name": "Yngwie"})
Blocos de tempo limite aninhados
Quando a execução insere um bloco de tempo limite aninhado, o tempo limite externo é pausado. Quando a execução sai do bloco de tempo limite aninhado, o tempo limite anterior é retomado.
Importante
Um bloqueio de tempo limite aninhado pode reduzir o prazo de um bloqueio de tempo limite externo, mas não pode estenda-o.
O exemplo seguinte mostra como utilizar chamadas aninhadas para o método 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()
No exemplo anterior, o código executa as seguintes etapas:
Linha 1: cria um bloco de tempo limite de cinco segundos.
- Linha 2: chama o método
find_one()
dentro do bloco de tempo limite de cinco segundos. O servidor deve - conclua esta operação dentro do tempo limite de cinco segundos.
- Linha 2: chama o método
Linha 3: cria um bloco de tempo limite de três segundos aninhado.
- Linha 4: chama o método
find_one()
dentro do bloco de tempo limite de três segundos. O servidor deve - conclua esta operação dentro de três segundos.
- Linha 4: chama o método
- Linha 5: chama o método
find_one()
fora do bloco de tempo limite de três segundos. O servidor deve - conclua esta operação dentro do tempo limite original de cinco segundos.
- Linha 5: chama o método
Linha 6: cria um bloco de tempo limite de dez segundos aninhado.
- Linha 7: chama o método
find_one()
dentro do bloco de tempo limite de dez segundos. Um tempo limite aninhado - o bloco não pode estender um bloco de tempo limite externo, portanto, o servidor deve concluir essa operação dentro do tempo limite original de cinco segundos.
- Linha 7: chama o método
Linha 8: chama o método
find_one()
fora do bloco de tempo limite de dez segundos. O servidor deve concluir esta operação dentro do tempo limite original de cinco segundos.
Segurança de thread e tarefa
O método timeout()
é seguro para thread. O tempo limite se aplica somente ao thread atual, e vários threads podem configurar diferentes tempos limite em paralelo.
O método timeout()
também é asyncio
seguro. O tempo limite se aplica apenas à Tarefa atual, e várias Tarefas podem configurar tempos limite diferentes ao mesmo tempo.
O exemplo a seguir mostra como usar o timeout()
método com Motor, o driver Python do MongoDB para aplicativos assíncronos:
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"})
Opção de conexão timeoutMS
Para especificar um tempo limite ao se conectar a um sistema do MongoDB, defina a opção de conexão timeoutMS
para o comprimento de tempo limite, em milissegundos. Você pode fazer isso de duas maneiras: passando um argumento para o construtor MongoClient
ou por meio de um parâmetro em sua connection string.
Os seguintes exemplos de código utilizam a opção timeoutMS
para especificar um tempo limite de 10 segundos:
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)
Se você especificar a opção timeoutMS
, o PyMongo aplicará automaticamente o tempo limite especificado para cada operação do servidor. Os exemplos de código a seguir especificam um tempo limite de 10 segundos e, em seguida, chamam os métodos insert_one()
e find_one()
. Para ver como a opção timeoutMS
se compara ao uso do método timeout()
, selecione a guia correspondente.
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"})
Importante
timeout() Substitui timeoutMS
Se você especificar a opção timeoutMS
e, em seguida, chamar o método timeout()
em seu código, o PyMongo ignorará o valor timeoutMS
dentro do bloco timeout
:
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
Tratamento de exceções
Quando uma operação de servidor excede o tempo limite especificado, o PyMongo gera uma exceção de tempo limite e define a propriedade PyMongoError.timeout
como True
.
O exemplo de código a seguir mostra uma maneira de lidar com uma exceção de tempo limite. Dentro do bloco except
, o código verifica a propriedade timeout
para determinar se a exceção foi causada por um tempo limite.
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}")
Solução de problemas
As seções a seguir descrevem erros que você pode ver ao usar tempos limite.
ServerSelectionTimeoutError
Este erro indica que o cliente não conseguiu encontrar um servidor disponível para executar a operação dentro do tempo limite fornecido:
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
Esse erro indica que o cliente não conseguiu estabelecer uma conexão dentro do tempo limite fornecido ou que a operação foi enviada, mas o servidor não responde a tempo:
pymongo.errors.NetworkTimeout: localhost:27017: timed out
ExecutionTimeout
Esse erro pode indicar que o servidor cancelou a operação porque excedeu o tempo limite fornecido. Mesmo que o PyMongo gere essa exceção, a operação pode ter sido concluída parcialmente no servidor.
pymongo.errors.ExecutionTimeout: operation exceeded time limit, full error: {'ok': 0.0, 'errmsg': 'operation exceeded time limit', 'code': 50, 'codeName': 'MaxTimeMSExpired'}
Isso também pode indicar que o cliente cancelou a operação porque não foi possível concluí-la dentro do tempo limite fornecido:
pymongo.errors.ExecutionTimeout: operation would exceed time limit, remaining timeout:0.00196 <= network round trip time:0.00427
WTimeoutError
Este erro indica que o servidor não conseguiu concluir a operação de gravação solicitada dentro do tempo limite fornecido e após a write concern especificada:
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
Esse erro indica que o servidor não conseguiu concluir um método insert_many()
ou bulk_write()
dentro do tempo limite fornecido e após a write concern especificada:
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': []}
Documentação da API
Para saber mais sobre como usar tempos limite no PyMongo, consulte a seguinte documentação da API: