asyncioから同期Python SDKを使用する

著者:solvethree読了時間:1分

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 に渡した 8 件のジョブのうち、同時に 4 件を実行可能にします。空きを待っているジョブは、まだ SDK 呼び出しを開始していません。
  • 各ワーカーは、スレッド間でクライアントを共有せず、それぞれ独自の Solvethree クライアントを作成します。
  • SDK の timeout=180 が解決処理の期限を設定します。セマフォの待機時間は含まれません。await の外側に asyncio のタイムアウトを設定しても、この SDK の期限の代わりにはなりません。
  • タスクとその requestId は、ワーカーに入る前に作成されます。エラーが発生するたびに代わりの ID を生成するのではなく、復旧に使えるよう両方を保持してください。

SDK はタスクを 1 回だけ作成し、準備完了になるかエラーが発生するまでポーリングします。solve の外側に別のポーリングループを書く必要はありません。

キャンセルしてもワーカーやリモートタスクは停止しない

to_thread を待機しているコルーチンをキャンセルしても、実行中のスレッドは停止せず、リモートの解決処理もキャンセルされません。サンプルの通常の例外ハンドラーは、キャンセル時のクリーンアップを行うものではありません。

これは同時実行数の制限にも影響します。キャンセルによりセマフォが解放されても、ワーカーは処理を続けることがあります。すぐに代わりのジョブを実行すると、4 件を超える SDK 呼び出しがアクティブなままになる可能性があります。キャンセル時にも厳密な制限が必要な場合は、未完了のワーカーを追跡し、完了するまでその分の実行枠を確保し続けてください。

本番環境では、コルーチンの終了後も復旧処理からアクセスできる場所に、正確なタスク入力とリクエスト ID を保持してください。タイムアウトは結果の受信を待つのをやめたことを意味し、必ずしもタスク作成が失敗したことを意味しません。

  1. 1.

    既知のタスクを復旧する

    Python SDK のエラーの task_id と request_id を確認してください。タスク ID がある場合は、別のタスクを作成せずに get_task で取得を再開します。

  2. 2.

    中断された作成処理を復旧する

    タスク ID がない場合は、元の requestId と完全に同じタスク入力を使って再送信します。作成が成功していれば、既存のタスクが返されます。同じ ID を再利用しながら入力を変更すると、競合が発生します。

  3. 3.

    失敗と中断を区別する

    TaskFailedError は、タスクが終端の失敗状態に達したことを意味します。errorCode と error を確認してください。ポーリングを続けたり、無効な入力を変更せずに無条件で再試行したりしないでください。HTTP エラーは、これとは別の層の失敗です。

ワーカーが結果を返したらソリューションを送信する

サンプルは準備完了になったタスクの ID を出力するだけで、対象には何も送信しません。その出力の後にあるコメントをアプリケーション固有の送信処理に置き換え、gather のすべてのジョブの完了を待たずに、ソリューションを速やかに使用してください。

返されたソリューションを、その userAgent、secChUa、解決時と同じプロキシとともに送信してください。SDK の successful_proxy ヘルパーは、元のタスクと準備完了の結果からプロキシを選択します。準備完了の結果はソリューションが生成されたことを意味するだけで、アプリケーションのリクエストが成功したことを意味しません。

最初のタスクを実行しましょう。

$5のワークスペースクレジットで始められます。

ワークスペースを作成
asyncioから同期Python SDKを使用する · solvethree