Use o SDK síncrono de Python a partir do asyncio

Por solvethree4 min de leitura

Use asyncio.to_thread para executar o método síncrono Solvethree.solve sem bloquear seu loop de eventos. Envolva a delegação com um semáforo e crie um cliente separado dentro de cada chamada de trabalho. O SDK não tem um cliente assíncrono nativo; suas requisições e consultas de polling continuam sendo executadas de forma síncrona na thread.

Nesta página

Limite o trabalho e defina o prazo do SDK

O exemplo requer Python 3.10+ e o SDK oficial de Python. Defina SOLVETHREE_API_KEY e SOLVETHREE_PROXY no ambiente do servidor. Substitua accounts.example.com e login pelo hostname e pela ação de destino. O site já deve ter um perfil ativo disponível para seu workspace; consulte a configuração do perfil do site.

asyncio · limitar o trabalho do 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.
  • O semáforo permite quatro trabalhos por vez entre os oito enviados a gather. Os trabalhos que aguardam uma vaga ainda não iniciaram sua chamada ao SDK.
  • Cada função de trabalho constrói seu próprio cliente Solvethree, em vez de compartilhar um entre threads.
  • O timeout=180 do SDK define o prazo para a resolução. O tempo de espera pelo semáforo não está incluído. Um timeout do asyncio em torno do await não substitui esse prazo do SDK.
  • A tarefa e seu requestId são criados antes de entrar na função de trabalho. Mantenha ambos disponíveis para recuperação, em vez de gerar um ID substituto sempre que ocorrer um erro.

O SDK cria a tarefa uma vez e faz polling até que ela esteja pronta ou lance um erro. Você não precisa escrever um segundo loop de polling em torno de solve.

O cancelamento não interrompe a thread de trabalho nem a tarefa remota

Cancelar a corrotina que aguarda to_thread não interrompe uma thread já em execução nem cancela a resolução remota. O handler de exceções comuns do exemplo não faz a limpeza necessária no cancelamento.

Isso também afeta o limite de concorrência: o cancelamento pode liberar o semáforo enquanto a thread de trabalho continua. Se você admitir trabalhos substitutos imediatamente, mais de quatro chamadas ao SDK poderão permanecer ativas. Se precisar de um limite rígido durante o cancelamento, acompanhe os trabalhos ainda em execução e mantenha a capacidade deles ocupada até que terminem.

Para uso em produção, armazene os parâmetros exatos da tarefa e o ID da requisição em algum lugar acessível ao seu fluxo de recuperação após a saída da corrotina. Um timeout significa que você parou de receber um resultado, não necessariamente que a criação da tarefa falhou.

  1. 1.

    Recupere uma tarefa conhecida

    Inspecione task_id e request_id do erro do SDK de Python. Se você tiver um ID de tarefa, retome a consulta com get_task em vez de criar outra tarefa.

  2. 2.

    Recupere uma criação interrompida

    Se você não tiver um ID de tarefa, reenvie os mesmos parâmetros da tarefa com o requestId original. Isso retorna a tarefa existente se a criação tiver sido bem-sucedida. Alterar os parâmetros e reutilizar esse ID gera um conflito.

  3. 3.

    Diferencie falha de interrupção

    Um TaskFailedError significa que a tarefa atingiu um estado terminal de falha. Inspecione seus campos errorCode e error; não continue consultando a tarefa nem repita cegamente parâmetros inválidos sem alterá-los. Erros HTTP são uma camada de falha separada.

Envie a solução quando a função de trabalho retornar

O exemplo imprime o ID da tarefa pronta; ele não envia nada ao destino. Substitua o comentário após essa impressão pelo envio específico da sua aplicação e use a solução prontamente, em vez de esperar que todos os trabalhos em gather terminem.

Envie a solução retornada com seus campos userAgent e secChUa e o mesmo proxy usado na resolução. O helper successful_proxy do SDK seleciona o proxy a partir da tarefa original e do resultado pronto. Um resultado pronto significa que uma solução foi gerada, não que a requisição da sua aplicação foi bem-sucedida.

Execute sua primeira tarefa.

Comece com $5 em créditos no espaço de trabalho.

Criar um espaço de trabalho
Use o SDK síncrono de Python a partir do asyncio · solvethree