Usa el SDK síncrono de Python desde asyncio

Por solvethree4 min de lectura

Usa asyncio.to_thread para ejecutar el método síncrono Solvethree.solve sin bloquear tu bucle de eventos. Usa un semáforo para limitar la delegación y crea un cliente independiente dentro de cada llamada al hilo de trabajo. El SDK no tiene un cliente asíncrono nativo; sus solicitudes y el sondeo siguen ejecutándose de forma síncrona en el hilo.

En esta página

Limitar el trabajo y establecer el plazo del SDK

El ejemplo requiere Python 3.10+ y el SDK oficial de Python. Configura SOLVETHREE_API_KEY y SOLVETHREE_PROXY en el entorno de tu servidor. Sustituye accounts.example.com y login por el nombre de host y la acción de tu destino. El sitio ya debe tener un perfil activo disponible para tu espacio de trabajo; consulta la configuración del perfil del sitio.

asyncio · limitar el trabajo del SDK síncrono
import asyncio
import os
import uuid
from solvethree import Solvethree

async def main():
    limit = asyncio.Semaphore(4)
    async def solve_one(number):
        task = {"site": "accounts.example.com", "action": "login", "proxy": os.environ["SOLVETHREE_PROXY"], "requestId": str(uuid.uuid4())}
        def blocking_solve():
            return Solvethree(os.environ["SOLVETHREE_API_KEY"]).solve(task, timeout=180)
        async with limit:
            try:
                result = await asyncio.to_thread(blocking_solve)
                print("Ready task:", result["id"])
                # Submit the solution now with its proxy and browser identity.
            except Exception as error:
                print("Job", number, "requestId", task["requestId"], "error class", type(error).__name__)
                # Retain task and inspect SDK recovery IDs before restarting it.
    await asyncio.gather(*(solve_one(number) for number in range(8)))

asyncio.run(main())
# Canceling an await does not stop an already-running thread or remote task.
  • El semáforo admite cuatro trabajos a la vez de los ocho enviados a gather. Los trabajos que esperan una plaza aún no han iniciado su llamada al SDK.
  • Cada hilo de trabajo construye su propio cliente Solvethree en lugar de compartir uno entre hilos.
  • El parámetro timeout=180 del SDK establece el plazo de resolución. No incluye el tiempo de espera del semáforo. Un tiempo de espera de asyncio aplicado al await no sustituye este plazo del SDK.
  • La tarea y su requestId se crean antes de entrar en el hilo de trabajo. Conserva ambos para la recuperación en lugar de generar un ID nuevo cada vez que se produzca un error.

El SDK crea la tarea una sola vez y la sondea hasta que está lista o lanza un error. No necesitas escribir un segundo bucle de sondeo alrededor de solve.

La cancelación no detiene el hilo de trabajo ni la tarea remota

Cancelar la corrutina que espera a to_thread no detiene un hilo que ya está en ejecución ni cancela la resolución remota. El manejador de excepciones habitual del ejemplo no realiza la limpieza necesaria tras una cancelación.

Esto también afecta al límite de concurrencia: la cancelación puede liberar el semáforo mientras el hilo de trabajo continúa. Si admites inmediatamente trabajos de sustitución, pueden quedar activas más de cuatro llamadas al SDK. Si necesitas un límite estricto durante la cancelación, lleva un registro de los hilos de trabajo pendientes y mantén ocupada su capacidad hasta que terminen.

Para su uso en producción, conserva los datos exactos de la tarea y el ID de solicitud en un lugar al que tu lógica de recuperación pueda acceder después de que termine la corrutina. Un tiempo de espera agotado significa que has dejado de recibir un resultado, no necesariamente que la creación de la tarea haya fallado.

  1. 1.

    Recuperar una tarea conocida

    Inspecciona los campos task_id y request_id del error del SDK de Python. Si tienes un ID de tarea, reanuda la recuperación con get_task en lugar de crear otra tarea.

  2. 2.

    Recuperar una creación interrumpida

    Si no tienes un ID de tarea, vuelve a enviar exactamente los mismos datos de la tarea con el requestId original. Esto devuelve la tarea existente si la creación tuvo éxito. Cambiar los datos y reutilizar ese ID provoca un conflicto.

  3. 3.

    Distinguir un fallo de una interrupción

    Un TaskFailedError significa que la tarea alcanzó el estado terminal de fallo. Inspecciona sus campos errorCode y error; no sigas sondeándola ni reintentes a ciegas con los mismos datos no válidos. Los errores HTTP pertenecen a una capa de fallo distinta.

Enviar la solución cuando el hilo de trabajo devuelva el resultado

El ejemplo imprime el ID de la tarea lista; no envía nada al destino. Sustituye el comentario que sigue a esa impresión por el envío específico de tu aplicación y usa la solución cuanto antes, en lugar de esperar a que terminen todos los trabajos de gather.

Envía la solución devuelta con sus campos userAgent y secChUa, y el mismo proxy utilizado para resolverla. La función auxiliar successful_proxy del SDK selecciona el proxy a partir de la tarea original y el resultado listo. Un resultado listo significa que se ha generado una solución, no que la solicitud de tu aplicación haya tenido éxito.

Ejecuta tu primera tarea.

Empieza con $5 de crédito en tu espacio de trabajo.

Crear un espacio de trabajo
Usa el SDK síncrono de Python desde asyncio · solvethree