Использование синхронного Python SDK из asyncio
Используйте asyncio.to_thread, чтобы запускать синхронный метод Solvethree.solve, не блокируя цикл событий. Ограничьте передачу работы в потоки семафором и создавайте отдельный клиент внутри каждого вызова рабочего потока. В SDK нет нативного асинхронного клиента; его запросы и опрос по-прежнему выполняются синхронно в потоке.
На этой странице
Ограничьте параллелизм и задайте срок выполнения в SDK
Для примера требуются Python 3.10+ и официальный Python SDK. Задайте SOLVETHREE_API_KEY и SOLVETHREE_PROXY в окружении сервера. Замените accounts.example.com и login на имя целевого хоста и действие. Для сайта уже должен существовать активный профиль, доступный вашему рабочему пространству; см. настройку профиля сайта.
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.
Восстановление работы с известной задачей
Проверьте
task_idиrequest_idв ошибке Python SDK. Если у вас есть идентификатор задачи, возобновите получение черезget_task, а не создавайте новую задачу. - 2.
Восстановление прерванного создания
Если идентификатора задачи нет, повторно отправьте идентичные входные данные задачи с исходным
requestId. Если создание удалось, вернётся существующая задача. Изменение входных данных при повторном использовании этого идентификатора вызывает конфликт. - 3.
Различайте сбой и прерывание
TaskFailedErrorозначает, что задача перешла в конечный статус ошибки. Проверьте еёerrorCodeиerror; не продолжайте опрос и не повторяйте вслепую запрос с теми же некорректными входными данными. HTTP-ошибки — отдельный уровень сбоев.
Отправляйте решение, когда рабочий поток возвращает результат
Пример выводит идентификатор готовой задачи, но ничего не отправляет целевому сервису. Замените комментарий после этого вывода на отправку, соответствующую вашему приложению, и используйте решение сразу, не дожидаясь завершения всех заданий в gather.
Отправьте полученное решение с его userAgent, secChUa и тем же прокси, который использовался для решения. Вспомогательная функция SDK successful_proxy выбирает прокси на основе исходной задачи и готового результата. Готовый результат означает, что решение сгенерировано, а не что запрос вашего приложения выполнен успешно.
Источники и справочник API
Запустите первую задачу.
Начните с $5 на балансе рабочего пространства.