Overview
Al usar PyMongo para realizar una operación en el servidor, también puede limitar el tiempo que el servidor tiene para finalizarla. Para ello, especifique un tiempo de espera para la operación en el cliente. Este tiempo aplica todos los pasos necesarios para completar la operación, incluyendo la selección del servidor, la verificación de la conexión, la serialización y la ejecución en el servidor. Cuando expira el tiempo de espera, PyMongo genera una excepción de tiempo de espera.
Puede especificar un tiempo de espera de dos maneras: utilizando el timeout() método o utilizando la opción de conexión timeoutMS.
Método timeout()
Para especificar un tiempo de espera en su código, llame al método timeout() y pásele la duración del tiempo de espera, en segundos. Debe llamar al método timeout() en una instrucción with, como se muestra en el siguiente ejemplo:
with pymongo.timeout(10): collection.insert_one({"name": "Yngwie"})
En el ejemplo anterior, si la operación de inserción no finaliza en 10 segundos, PyMongo genera un error.
El tiempo de espera especificado se aplica a todas las operaciones dentro del bloque with. En el siguiente ejemplo, las operaciones de inserción y búsqueda deben finalizar en un total de 10 segundos:
with pymongo.timeout(10): coll.insert_one({"name": "Yngwie"}) coll.find_one({"name": "Yngwie"})
Bloques de tiempo de espera anidados
Cuando la ejecución entra en un bloque de timeout anidado, el timeout exterior se pausa. Cuando la ejecución sale del bloque anidado de tiempo de espera, se reanuda el tiempo de espera anterior.
Importante
Un bloque de tiempo de espera anidado puede acortar la fecha límite de un bloque de tiempo de espera externo, pero no puede extenderla.
El siguiente ejemplo muestra cómo utilizar llamadas anidadas al 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()
En el ejemplo anterior, el código realiza los siguientes pasos:
Línea:1 crea un bloque de tiempo de espera de cinco segundos.
- 2Línea: Llama al
find_one()método dentro del bloque de tiempo de espera de cinco segundos. El servidor debe - Complete esta operación dentro del tiempo de espera de cinco segundos.
- 2Línea: Llama al
Línea:3 crea un bloque de tiempo de espera anidado de tres segundos.
- 4Línea: Llama al
find_one()método dentro del bloque de tiempo de espera de tres segundos. El servidor debe - Complete esta operación en tres segundos.
- 4Línea: Llama al
- 5Línea: Llama al
find_one()método fuera del tiempo de espera de tres segundos. El servidor debe - Complete esta operación dentro del tiempo de espera original de cinco segundos.
- 5Línea: Llama al
Línea:6 crea un bloque de tiempo de espera anidado de diez segundos.
- 7Línea: Llama al
find_one()método dentro del bloque de tiempo de espera de diez segundos. Un tiempo de espera anidado - El bloque no puede extender un bloque externo de tiempo de espera, por lo que el servidor debe completar esta operación dentro del tiempo de espera original de cinco segundos.
- 7Línea: Llama al
8Línea: Llama al
find_one()método fuera del tiempo de espera de diez segundos. El servidor debe completar esta operación dentro del tiempo de espera original de cinco segundos.
Seguridad de subprocesos y tareas
El método timeout() es seguro para subprocesos. El tiempo de espera solo se aplica al subproceso actual, y varios subprocesos pueden configurar diferentes tiempos de espera en paralelo.
El método timeout() también es seguro contra asyncio. El tiempo de espera solo se aplica a la tarea actual, y varias tareas pueden configurar diferentes tiempos de espera simultáneamente.
El siguiente ejemplo muestra cómo utilizar el método timeout() con
Motor, el controlador Python de MongoDB para aplicaciones asincrónicas:
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"})
Opción de conexión timeoutMS
Para especificar un tiempo de espera al conectarse a una implementación de MongoDB, configure la opción de conexión timeoutMS con la duración del tiempo de espera, en milisegundos. Puede hacerlo de dos maneras: pasando un argumento al constructor MongoClient o mediante un parámetro en su cadena de conexión.
Los siguientes ejemplos de código utilizan la opción timeoutMS para especificar un tiempo de espera 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)
Si especifica la opción timeoutMS, PyMongo aplica automáticamente el tiempo de espera especificado a cada operación del servidor. Los siguientes ejemplos de código especifican un tiempo de espera de 10 segundos y luego invocan los métodos insert_one() y find_one(). Para comparar la opción timeoutMS con el método timeout(), seleccione la pestaña correspondiente.
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() Anula timeoutMS
Si especifica la opción timeoutMS y luego llama al método timeout() en su código, PyMongo ignora el valor timeoutMS dentro del bloque 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
Manejo de excepciones
Cuando una operación del servidor excede el tiempo de espera especificado, PyMongo genera una excepción de tiempo de espera y establece la propiedad PyMongoError.timeout en True.
El siguiente ejemplo de código muestra una forma de gestionar una excepción de tiempo de espera. Dentro del bloque except, el código comprueba la propiedad timeout para determinar si la excepción se debió a un tiempo de espera.
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}")
Solución de problemas
Las siguientes secciones describen errores que puede ver al usar tiempos de espera.
Error de tiempo de espera de selección del servidor
Este error indica que el cliente no pudo encontrar un servidor disponible para ejecutar la operación dentro del tiempo de espera indicado:
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
Este error indica que el cliente no pudo establecer una conexión dentro del tiempo de espera dado o que la operación se envió pero el servidor no respondió a tiempo:
pymongo.errors.NetworkTimeout: localhost:27017: timed out
Tiempo de espera de ejecución
Este error podría indicar que el servidor canceló la operación porque se excedió el tiempo de espera establecido. Incluso si PyMongo genera esta excepción, es posible que la operación se haya completado parcialmente en el servidor.
pymongo.errors.ExecutionTimeout: operation exceeded time limit, full error: {'ok': 0.0, 'errmsg': 'operation exceeded time limit', 'code': 50, 'codeName': 'MaxTimeMSExpired'}
También podría indicar que el cliente canceló la operación porque no fue posible completarla dentro del tiempo de espera indicado:
pymongo.errors.ExecutionTimeout: operation would exceed time limit, remaining timeout:0.00196 <= network round trip time:0.00427
Error de tiempo de espera
Este error indica que el servidor no pudo completar la operación de escritura solicitada dentro del tiempo de espera indicado y siguiendo el problema de escritura especificado:
pymongo.errors.WTimeoutError: operation exceeded time limit, full error: {'code': 50, 'codeName': 'MaxTimeMSExpired', 'errmsg': 'operation exceeded time limit', 'errInfo': {'writeConcern': {'w': 1, 'wtimeout': 0}}}
Error de escritura masiva
Este error indica que el servidor no pudo completar un método insert_many() o bulk_write() dentro del tiempo de espera indicado y siguiendo el problema de escritura especificado:
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': []}
Documentación de la API
Para obtener más información sobre el uso de timeouts en PyMongo, consulta la siguiente documentación de la API: