メインコンテンツへスキップ
Webhookのサポートを積極的に拡大しています。新機能: 指数バックオフによる自動再試行 — 失敗した配信は30分間に最大5回再試行されます。近日公開予定:
  • チーム全体のデフォルトWebhook URL
  • ペイロード検証のための暗号署名
早期アクセスをご希望ですか?info@olostep.comまでご連絡いただくか、Slackコミュニティに参加してください。

概要

Webhookは、長時間実行される操作が完了したときに、リアルタイムのHTTP POST通知をサーバーに送信します。ステータスをポーリングする代わりに、アプリケーションは即時の更新を受け取ります。

使用例

非同期処理

バッチやクロールが完了したときに通知を受け取り、ポーリングを避ける

パイプラインのトリガー

データが準備できたときに自動的に下流の処理をトリガーする

アラート

完了時にSlack、メール、その他のシステムにアラートを送信する

データ同期

データベースをOlostepの結果と同期させる

サポートされているイベント

バッチの処理が完了したときに発生します(すべてのアイテムが完了または失敗)。
{
  "id": "event_a1b2c3d4e5f6g7h8",
  "object": "event.batch.completed",
  "timestamp": 1737570000000,
  "delivery_attempt": "1/5",
  "data": {
    "id": "batch_xyz123",
    "object": "batch",
    "status": "completed",
    "items_total": 100,
    "items_completed": 98,
    "items_failed": 2,
    "created_at": "2024-01-15T10:00:00Z",
    "completed_at": "2024-01-15T10:05:32Z"
  }
}
クロールが完了し、発見されたすべてのページが処理されたときに発生します。
{
  "id": "event_x9y8z7w6v5u4t3s2",
  "object": "event.crawl.completed",
  "timestamp": 1737570000000,
  "delivery_attempt": "1/5",
  "data": {
    "id": "crawl_abc789",
    "object": "crawl",
    "status": "completed",
    "start_url": "https://example.com",
    "urls_count": 87,
    "max_pages": 100,
    "max_depth": 3,
    "actual_max_depth": 3,
    "start_epoch": 1737569500000,
    "start_date": "2024-01-15"
  }
}

Webhookの設定

リソースを作成するときにwebhookを渡します。このURLが完了通知を受け取ります。
パラメータ名: 標準のパラメータはwebhookです。後方互換性のために、webhook_urlもエイリアスとして受け入れられます。
import requests

# バッチの例
response = requests.post(
    "https://api.olostep.com/v1/batches",
    headers={"Authorization": "Bearer <YOUR_API_KEY>"},
    json={
        "items": [
            {"url": "https://example.com/page1", "custom_id": "1"},
            {"url": "https://example.com/page2", "custom_id": "2"}
        ],
        "webhook": "https://your-server.com/webhooks/olostep"
    }
)

# クロールの例
response = requests.post(
    "https://api.olostep.com/v1/crawls",
    headers={"Authorization": "Bearer <YOUR_API_KEY>"},
    json={
        "start_url": "https://example.com",
        "max_pages": 50,
        "webhook": "https://your-server.com/webhooks/olostep"
    }
)

Webhookペイロード

すべてのWebhookペイロードは統一されたエンベロープ構造に従います:
{
  "id": "event_a1b2c3d4e5f6g7h8",
  "object": "event.batch.completed",
  "timestamp": 1737570000000,
  "delivery_attempt": "1/5",
  "data": {
    "id": "batch_xyz123",
    "object": "batch",
    "status": "completed",
    "items_total": 100,
    "items_completed": 98,
    "items_failed": 2
  }
}

エンベロープフィールド

フィールド説明
idイベントID — すべての再試行で同じ
objectイベントタイプ(例: event.batch.completed
timestampこの配信試行が送信された時刻(エポックミリ秒)
delivery_attempt現在の試行 / 最大試行回数(例: 1/5, 3/5
data実際のリソースデータ(APIレスポンスと同じ形式)
idフィールドを使用して、受信側でWebhookの重複配信を排除します。同じイベントIDがすべての再試行で表示されます。

再試行の動作

失敗したWebhook配信は、30分間のウィンドウで指数バックオフを使用して自動的に再試行されます:
試行試行前の遅延累積時間
1即時0分
2約2分約2分
3約4分約6分
4約7分約13分
5約15分約28分
合計再試行ウィンドウ: 30分
リクエストごとのタイムアウト: 30秒

成功と見なされる条件

エンドポイントは30秒以内に2xxステータスコードを返す必要があります。それ以外のレスポンスは再試行をトリガーします。
レスポンス結果
200 OK✅ 配信済み
201 Created✅ 配信済み
301 Redirect❌ 再試行(リダイレクトは追跡しません)
400 Bad Request❌ 再試行
500 Server Error❌ 再試行
タイムアウト (>30s)❌ 再試行
接続拒否❌ 再試行

ベストプラクティス

200 OKを即座に返し、Webhookを非同期で処理します。処理が30秒以上かかる場合、再試行されるため、重複配信が発生します。
from queue import Queue
import threading

webhook_queue = Queue()

@app.route('/webhooks/olostep', methods=['POST'])
def handle_webhook():
    # 非同期処理のためにキューに入れる
    webhook_queue.put(request.json)
    
    # 即座に返す
    return 'OK', 200

def process_webhooks():
    while True:
        event = webhook_queue.get()
        # ここで遅い処理が行われる
        process_event(event)

threading.Thread(target=process_webhooks, daemon=True).start()
idフィールドを使用して重複を排除します。処理済みのイベントIDを保存し、重複をスキップします。
processed_events = set()  # 本番環境ではRedis/DBを使用

def handle_event(event):
    if event['id'] in processed_events:
        return  # すでに処理済み
    
    # イベントを処理する
    process_batch_completed(event['data'])
    
    # 処理済みとしてマーク
    processed_events.add(event['id'])
デバッグのためにすべてのWebhook受信をログに記録します。イベントID、タイムスタンプ、処理結果を含めます。
import logging

@app.route('/webhooks/olostep', methods=['POST'])
def handle_webhook():
    event = request.json
    logging.info(f"Webhook received: id={event['id']} type={event['object']} attempt={event['delivery_attempt']}")
    
    try:
        process_event(event)
        logging.info(f"Webhook processed: id={event['id']}")
    except Exception as e:
        logging.error(f"Webhook failed: id={event['id']} error={e}")
        raise
    
    return 'OK', 200
常にWebhookエンドポイントにはHTTPSを使用してください。HTTPエンドポイントは盗聴や中間者攻撃に対して脆弱です。

トラブルシューティング

  1. リクエストにwebhookパラメータが含まれていることを確認する
  2. エンドポイントが公開アクセス可能であることを確認する(localhostではない)
  3. サーバーログで受信リクエストを確認する
  4. 2xxステータスコードを返していることを確認する
これは再試行中に予想される動作です。idフィールドを使用して冪等性のある処理を実装します:
def handle_event(event):
    if already_processed(event['id']):
        return  # 重複をスキップ
    
    process_event(event)
    mark_processed(event['id'])
エンドポイントは30秒以内に応答する必要があります。Webhookを非同期で処理します:
@app.route('/webhooks', methods=['POST'])
def webhook():
    queue.enqueue(process_webhook, request.json)
    return 'OK', 200  # 即座に応答

近日公開予定

チームデフォルトURL

アカウント設定でデフォルトのWebhook URLを設定します。すべてのリクエストはこのURLを使用しますが、上書き可能です。

署名検証

OlostepからのWebhookペイロードであることを確認するための暗号署名(HMAC-SHA256)。
これらの機能への早期アクセスをご希望ですか?info@olostep.comまでご連絡いただくか、Slackコミュニティに参加してください。