Использование синхронного Python SDK из asyncio

Автор: solvethree3 мин на чтение

Используйте asyncio.to_thread, чтобы запускать синхронный метод Solvethree.solve, не блокируя цикл событий. Ограничьте передачу работы в потоки семафором и создавайте отдельный клиент внутри каждого вызова рабочего потока. В SDK нет нативного асинхронного клиента; его запросы и опрос по-прежнему выполняются синхронно в потоке.

На этой странице

Ограничьте параллелизм и задайте срок выполнения в SDK

Для примера требуются Python 3.10+ и официальный Python SDK. Задайте SOLVETHREE_API_KEY и SOLVETHREE_PROXY в окружении сервера. Замените accounts.example.com и login на имя целевого хоста и действие. Для сайта уже должен существовать активный профиль, доступный вашему рабочему пространству; см. настройку профиля сайта.

asyncio · ограничение объёма работы синхронного SDK
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.
  • Семафор допускает одновременное выполнение четырёх заданий из восьми, переданных в gather. Задания, ожидающие свободного места, ещё не начали вызов SDK.
  • Каждый рабочий поток создаёт собственный клиент Solvethree, а не использует общий клиент для нескольких потоков.
  • Параметр SDK timeout=180 задаёт предельное время решения. Время ожидания семафора в него не входит. Тайм-аут asyncio вокруг await не заменяет этот срок, заданный в SDK.
  • Задача и её requestId создаются до входа в рабочий поток. Сохраняйте оба значения для восстановления, а не генерируйте новый идентификатор при каждой ошибке.

SDK создаёт задачу один раз и опрашивает её до готовности либо возникновения исключения. Писать второй цикл опроса вокруг solve не нужно.

Отмена не останавливает рабочий поток или задачу на сервере

Отмена корутины, ожидающей to_thread, не останавливает уже работающий поток и не отменяет решение на сервере. Обычный обработчик исключений в примере не выполняет очистку при отмене.

Это также влияет на ограничение параллелизма: отмена может освободить семафор, пока рабочий поток продолжает работу. Если сразу допустить новые задания взамен отменённых, активными могут остаться более четырёх вызовов SDK. Если при отмене требуется строгое ограничение, отслеживайте незавершённые рабочие потоки и сохраняйте занятые ими места до их завершения.

В рабочей среде сохраняйте точные входные данные задачи и идентификатор запроса там, где механизм восстановления сможет получить их после завершения корутины. Тайм-аут означает, что вы перестали получать результат, а не обязательно то, что создание задачи не удалось.

  1. 1.

    Восстановление работы с известной задачей

    Проверьте task_id и request_id в ошибке Python SDK. Если у вас есть идентификатор задачи, возобновите получение через get_task, а не создавайте новую задачу.

  2. 2.

    Восстановление прерванного создания

    Если идентификатора задачи нет, повторно отправьте идентичные входные данные задачи с исходным requestId. Если создание удалось, вернётся существующая задача. Изменение входных данных при повторном использовании этого идентификатора вызывает конфликт.

  3. 3.

    Различайте сбой и прерывание

    TaskFailedError означает, что задача перешла в конечный статус ошибки. Проверьте её errorCode и error; не продолжайте опрос и не повторяйте вслепую запрос с теми же некорректными входными данными. HTTP-ошибки — отдельный уровень сбоев.

Отправляйте решение, когда рабочий поток возвращает результат

Пример выводит идентификатор готовой задачи, но ничего не отправляет целевому сервису. Замените комментарий после этого вывода на отправку, соответствующую вашему приложению, и используйте решение сразу, не дожидаясь завершения всех заданий в gather.

Отправьте полученное решение с его userAgent, secChUa и тем же прокси, который использовался для решения. Вспомогательная функция SDK successful_proxy выбирает прокси на основе исходной задачи и готового результата. Готовый результат означает, что решение сгенерировано, а не что запрос вашего приложения выполнен успешно.

Запустите первую задачу.

Начните с $5 на балансе рабочего пространства.

Создать рабочее пространство
Использование синхронного Python SDK из asyncio · solvethree