Skip to content

Webhooks

أرسل إشعارات webhook عبر HTTP موقّعة بـ HMAC من Potato لسبعة أنواع من أحداث التعليق، مع إعادة محاولة بتراجع أسّي، ومراقبة إدارية، وتحقق بـ Python وNode.

جديد في الإصدار v2.4.0

تتيح الـ webhooks لـ Potato إشعار الأنظمة الخارجية حين تقع أحداث التعليق، من دون استطلاع دوري. اربطها بخطوط معالجة البيانات، أو أطلق تنبيهات، أو حدّث لوحات المعلومات، أو ابدأ معالجة لاحقة تلقائياً.

نظرة عامة

يرسل Potato طلب HTTP POST إلى نقطة النهاية التي هيّأتها كلما وقع حدث مدعوم. والحمولات بصيغة JSON وموقّعة بـ HMAC-SHA256 حتى تتحقق من أنها جاءت من نسختك من Potato.

وتسليم الـ webhook غير حاجب بالكامل، فلا تتأخر طلبات التعليق أبداً بينما الـ webhooks في الطريق. أما التسليمات الفاشلة فيُعاد تجريبها بتراجع أسّي.

التهيئة

أضف قسم webhooks إلى تهيئة YAML لديك:

yaml
webhooks:
  enabled: true
  endpoints:
    - name: "my-pipeline"
      url: "https://your-system.example.com/potato-events"
      secret: "your-signing-secret"        # optional but recommended
      events:
        - annotation.created
        - item.fully_annotated
        - task.completed
      active: true
      timeout: 10

نقاط نهاية متعددة

يمكنك تهيئة عدة نقاط نهاية، لكل واحدة اشتراكات أحداث مختلفة:

yaml
webhooks:
  enabled: true
  endpoints:
    - name: "data-pipeline"
      url: "https://pipeline.example.com/annotations"
      secret: ${WEBHOOK_SECRET_1}
      events:
        - annotation.created
        - item.fully_annotated
    - name: "slack-alerts"
      url: "https://hooks.slack.com/services/..."
      events:
        - task.completed
        - quality.attention_check_failed
    - name: "catch-all"
      url: "https://logging.example.com/potato"
      events:
        - "*"          # subscribe to all events

أنواع الأحداث

الحدثيقع حين
annotation.createdيرسل معلّق وسماً لعنصر
annotation.updatedيعدّل معلّق وسماً أرسله سابقاً
item.fully_annotatedيبلغ عنصر عدد التداخل المطلوب من التعليقات
task.completedتكتمل تعليقات كل العناصر في المهمة
user.phase_completedينهي معلّق مرحلة (سير عمل الوضع المنفرد)
quality.attention_check_failedيخفق معلّق في فحص انتباه
webhook.testيُطلق يدوياً عبر واجهة الإدارة للاختبار

استخدم "*" للاشتراك في كل أنواع الأحداث الحالية والمستقبلية.

صيغة الحمولة

تتشارك كل الأحداث في مغلّف واحد:

json
{
  "event_id": "evt_01HXYZ...",
  "event_type": "annotation.created",
  "timestamp": "2026-03-17T14:23:01Z",
  "task_name": "sentiment-study",
  "data": {
    ...
  }
}

حمولة annotation.created

json
{
  "event_type": "annotation.created",
  "data": {
    "annotator_id": "user123",
    "instance_id": "doc_042",
    "annotation": {
      "sentiment": "positive",
      "confidence": "high"
    },
    "submitted_at": "2026-03-17T14:23:01Z"
  }
}

حمولة item.fully_annotated

json
{
  "event_type": "item.fully_annotated",
  "data": {
    "instance_id": "doc_042",
    "annotator_count": 3,
    "annotations": [
      {"annotator_id": "user1", "sentiment": "positive"},
      {"annotator_id": "user2", "sentiment": "positive"},
      {"annotator_id": "user3", "sentiment": "neutral"}
    ]
  }
}

حمولة task.completed

json
{
  "event_type": "task.completed",
  "data": {
    "task_name": "sentiment-study",
    "total_instances": 500,
    "total_annotations": 1500,
    "completed_at": "2026-03-17T15:00:00Z"
  }
}

التحقق من التواقيع

حين يكون secret مهيّأً، يوقّع Potato كل طلب باستخدام Standard Webhooks (HMAC-SHA256). وتُضمَّن ثلاث ترويسات:

الترويسةالقيمة
webhook-idمعرّف تسليم فريد
webhook-timestampطابع Unix الزمني للتسليم
webhook-signatureتوقيع HMAC-SHA256

التحقق في Python

python
import hmac
import hashlib
import time
 
def verify_webhook(payload_bytes: bytes, headers: dict, secret: str) -> bool:
    webhook_id = headers.get("webhook-id", "")
    timestamp = headers.get("webhook-timestamp", "")
    signature = headers.get("webhook-signature", "")
 
    # Reject stale requests (older than 5 minutes)
    if abs(time.time() - int(timestamp)) > 300:
        return False
 
    signed_content = f"{webhook_id}.{timestamp}.{payload_bytes.decode()}"
    expected = hmac.new(
        secret.encode(),
        signed_content.encode(),
        hashlib.sha256
    ).hexdigest()
 
    return hmac.compare_digest(f"v1,{expected}", signature)

التحقق في Node.js

javascript
const crypto = require('crypto');
 
function verifyWebhook(payload, headers, secret) {
  const webhookId = headers['webhook-id'];
  const timestamp = headers['webhook-timestamp'];
  const signature = headers['webhook-signature'];
 
  // Reject stale requests
  if (Math.abs(Date.now() / 1000 - parseInt(timestamp)) > 300) {
    return false;
  }
 
  const signedContent = `${webhookId}.${timestamp}.${payload}`;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(signedContent)
    .digest('hex');
 
  return crypto.timingSafeEqual(
    Buffer.from(`v1,${expected}`),
    Buffer.from(signature)
  );
}

سلوك إعادة المحاولة

تُعاد محاولة التسليمات الفاشلة (استجابة خارج نطاق 2xx أو انتهاء مهلة) تلقائياً:

المحاولةالتأخير
1 (الأولى)فوراً
25 ثوانٍ
330 ثانية
45 دقائق
530 دقيقة
6ساعة واحدة

وبعد ست محاولات فاشلة، يُوسم التسليم بأنه فاشل نهائياً. ويُحفظ طابور إعادة المحاولة في SQLite في {output_dir}/.webhooks/webhook_retries.db، فتبقى المحاولات المعلّقة بعد إعادة تشغيل الخادم.

المراقبة والاختبار

واجهة الإدارة

اطّلع على حالة الـ webhooks وإحصاءاتها:

bash
# List all webhooks and their delivery statistics
curl -H "X-API-Key: $ADMIN_API_KEY" \
  http://localhost:8000/admin/api/webhooks

الاستجابة:

json
{
  "endpoints": [
    {
      "name": "my-pipeline",
      "url": "https://...",
      "events": ["annotation.created"],
      "active": true,
      "stats": {
        "total_emitted": 1240,
        "total_failed": 3,
        "pending_retries": 0,
        "last_success": "2026-03-17T14:23:01Z"
      }
    }
  ]
}

إرسال webhook تجريبي

bash
curl -X POST -H "X-API-Key: $ADMIN_API_KEY" \
  http://localhost:8000/admin/api/webhooks/test \
  -H "Content-Type: application/json" \
  -d '{"endpoint_name": "my-pipeline"}'

وهذا يطلق حدث webhook.test إلى نقطة النهاية المسمّاة فوراً.

مرجع التهيئة الكامل

yaml
webhooks:
  enabled: true
  endpoints:
    - name: string           # unique name for this endpoint
      url: string            # HTTPS URL to POST to
      secret: string         # optional HMAC secret for signature verification
      events:                # list of event types, or ["*"] for all
        - annotation.created
      active: true           # set false to disable without removing
      timeout: 10            # request timeout in seconds (default: 10)
      max_retries: 6         # max retry attempts (default: 6)

قراءات إضافية

للاطلاع على تفاصيل التنفيذ، انظر الوثائق المصدرية.