פיתוח לוח בקרה לניהול Webhooks

כאשר webhooks מפסיקים להגיע, האינטגרציות נכנסות לכאוס: הזמנות אובדות, לקוחות מתלוננים, ומציאת הגורם לבעיה אורכת שעות. אנחנו בונים לוח בקרה לניהול webhooks שהופך כל בקשה לשקופה—מהשליחה ועד לתגובת הנמען. הצוות שלנו מספק את הפרויקט במפתח מלא עם ניסיונות חוזרים אוטומטיים, חתימת HMAC וניטור, כך שתראו את תמונת המשלוח המלאה ותוכלו לפתור תקלות במהירות.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

אלה רק חלק מהסוגים הטכניים של אתרים שאנו עובדים איתם, ולכל אחד מהם יכולים להיות מאפיינים ופונקציונליות ספציפיים משלו, וכן ניתן להתאים אותם לצרכים ולמטרות הספציפיים של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
פיתוח לוח בקרה לניהול Webhooks
בינוני
~3-5 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1359
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113
  • פיתוח אתר עבור SBH Partners
    פיתוח אתר עבור SBH Partners
    1201
  • פיתוח אתר עבור Red Pear
    פיתוח אתר עבור Red Pear
    619

פיתוח לוח בקרה לניהול Webhook

תארו לעצמכם שמשיקים חנות מסחר אלקטרוני על Laravel, מחברים webhooks להודעות הזמנות ל-CRM ולטלגרם. חודש לאחר מכן, לקוחות מתלוננים שההזמנות לא מגיעות. אתם חופרים בלוגים של השרת — קילומטרים של שורות, grep לפי חותמת זמן — ועדיין לא רואים את התמונה המלאה. השגיאה נמצאת איפשהו בין timeout לתגובה שגויה של הנמען. המצב הזה מוכר לכל אינטגרטור. לוח הבקרה שלנו לניהול webhook פותר את זה: זמן הדיבוג הממוצע יורד מ-2–3 שעות ל-15 דקות.

אנחנו בונים לוחות בקרה אדמיניסטרטיביים למנויי Webhook שמעניקים שקיפות מלאה של אספקת ההודעות. במקום "קופסה שחורה", אתם מקבלים מערכת שבה כל שליחה, סטטוס, גוף בקשה וגוף תגובה מוצגים על המסך. ניסיונות חוזרים אוטומטיים, חתימת HMAC, idempotency — הכל מובנה בלוח הבקרה כברירת מחדל.

בעיות טיפוסיות ללא לוח בקרה: אתם לא יודעים אם ה-webhook הגיע, כמה ניסיונות נדרשו, מה הייתה התגובה. שגיאות בצד הנמען נשארות בלתי מזוהות עד לתלונת לקוח. לוח הבקרה שלנו מבטל את העיוורון הזה — אתם רואים כל בקשה בזמן אמת.

למה חתימת HMAC קריטית ל-Webhooks

Webhooks אינם מאובטחים: כל מי שיודע את ה-URL יכול לשלוח הודעה מזויפת. חתימת HMAC מבטיחה שהבקשה הגיעה מהשרת שלכם ולא שונתה. אנו מיישמים חתימה עם sha256 ו-השוואה חסינת תזמון — הגנה מפני התקפות timing. חתימת HMAC היא תקן בתעשייה; בלעדיה, ה-webhook שלכם יכול להיות מזויף, מה שיוביל לדליפת נתונים או לפעולות שגויות.

איך להבטיח Idempotency באספקה

במהלך כשלים או ניסיונות חוזרים, אותו אירוע עשוי להישלח פעמיים. אנו משתמשים ב-event_id ייחודי לכל אספקה, ומונעים כפילויות. מסד הנתונים בודק ייחודיות של צמד (event_id, endpoint_id) — שליחות כפולות מתעלמות.

Backoff אקספוננציאלי מגדיל את שיעור הצלחת האספקה פי 3 במהלך כשלים זמניים בהשוואה למרווחים קבועים.

השוואה: ללא לוח בקרה אתם מבזבזים שעות על קבצי לוג; עם לוח בקרה אתם רואים הכל בזמן אמת. לוח הבקרה שלנו מקצר את זמן דיבוג ה-webhook פי 5 בהשוואה לניתוח לוגים.

קריטריון ללא לוח בקרה עם לוח בקרה
ניטור לוגים של שרת, grep לוח בקרה עם סינון וחיפוש
ניסיונות חוזרים ידני או cron backoff אקספוננציאלי אוטומטי
אבטחה ללא חתימה HMAC + אימות חסין תזמון
זמן דיבוג שעות של ניתוח לוגים דקות

ניטור והתראות

לוח הבקרה כולל ניטור עם ספים: אם אחוז האספקות שנכשלו עולה על 10% בשעה האחרונה, אנו שולחים הודעה לטלגרם או ל-Slack. ניתן להגדיר כללי התראה מותאמים אישית ישירות מהממשק.

הוספת נקודת קצה חדשה ל-Webhook

תהליך ההוספה אורך פחות מדקה:

  1. פתחו את הקטע Endpoints בסרגל הצד.
  2. לחצו על הכפתור 'הוסף נקודת קצה'.
  3. הזינו את ה-URL של הנמען, בחרו סוגי אירועים (לדוגמה, order.created, order.shipped), הגדירו מפתח סודי ל-HMAC.
  4. הגדירו פרמטרי אספקה: timeout (ברירת מחדל 10 שניות), ניסיונות חוזרים מקסימליים (ברירת מחדל 5).
  5. שמרו. לוח הבקרה שולח אוטומטית ping לבדיקה כדי לוודא קישוריות.

לאחר מכן, נקודת הקצה מתחילה מיד לקבל webhooks עבור האירועים שנבחרו. כל האספקות מוצגות בלוג עם סינון ויכולת drill-down.

מדדי לוח בקרה

לוח הבקרה מספק את המדדים הבאים עבור כל נקודת קצה ובאופן גלובלי:

  • סך כל ה-webhooks שנשלחו (מפולח לפי סטטוס: נמסר, נכשל, בניסיון חוזר)
  • אחוז אספקות מוצלחות — אינדיקטור בריאות מרכזי של האינטגרציה
  • זמן תגובה ממוצע של הנמען (במילישניות)
  • מספר ניסיונות חוזרים והתפלגות הניסיונות
  • השגיאה האחרונה ולוג ניסיונות מלא עם גופי בקשה ותגובה

כל המדדים מתעדכנים בזמן אמת וזמינים כטבלאות וגרפים. ניתן להגדיר התראות אוטומטיות כאשר חריגים ספים — לדוגמה, אם אחוז השגיאות עולה על 10% בשעה האחרונה.

סכמת מסד נתונים

CREATE TABLE webhook_endpoints (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    url TEXT NOT NULL,
    secret VARCHAR(64) NOT NULL, -- для HMAC-подписи
    events TEXT[] NOT NULL, -- ['order.created', 'order.shipped']
    is_active BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),
    -- Настройки доставки
    timeout_ms INTEGER DEFAULT 10000,
    max_retries SMALLINT DEFAULT 5,
    -- Статистика (денормализованная для быстрого отображения)
    total_sent INTEGER DEFAULT 0,
    total_failed INTEGER DEFAULT 0,
    last_sent_at TIMESTAMPTZ,
    last_error TEXT
);

CREATE TABLE webhook_deliveries (
    id BIGSERIAL PRIMARY KEY,
    endpoint_id INTEGER REFERENCES webhook_endpoints(id),
    event_type VARCHAR(100) NOT NULL,
    event_id VARCHAR(100) NOT NULL, -- идемпотентный ключ события
    payload JSONB NOT NULL,
    status VARCHAR(20) DEFAULT 'pending', -- pending, delivered, failed, retrying
    attempt_count SMALLINT DEFAULT 0,
    next_retry_at TIMESTAMPTZ,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    delivered_at TIMESTAMPTZ,
    -- HTTP-детали последней попытки
    last_http_status SMALLINT,
    last_response_body TEXT,
    last_request_ms INTEGER,
    last_error_message TEXT
);

CREATE TABLE webhook_delivery_attempts (
    id BIGSERIAL PRIMARY KEY,
    delivery_id BIGINT REFERENCES webhook_deliveries(id),
    attempt_num SMALLINT NOT NULL,
    attempted_at TIMESTAMPTZ DEFAULT NOW(),
    http_status SMALLINT,
    request_ms INTEGER,
    request_body TEXT,
    response_body TEXT,
    error TEXT
);

CREATE INDEX ON webhook_deliveries (endpoint_id, created_at DESC);
CREATE INDEX ON webhook_deliveries (status, next_retry_at) WHERE status = 'retrying';
CREATE INDEX ON webhook_deliveries (event_id, endpoint_id) UNIQUE;

שירות אספקה

class WebhookDeliveryService {
    public function dispatch(string $eventType, string $eventId, array $payload): void {
        // Находим активные endpoints, подписанные на это событие
        $endpoints = $this->endpointRepo->findActiveForEvent($eventType);
        foreach ($endpoints as $endpoint) {
            // Идемпотентность: не дублируем если уже создали запись для этого события
            $delivery = $this->deliveryRepo->findOrCreate(
                $endpoint->id,
                $eventId,
                [
                    'event_type' => $eventType,
                    'payload' => $payload,
                    'status' => 'pending',
                ]
            );
            // Ставим в очередь на асинхронную отправку
            dispatch(new DeliverWebhookJob($delivery->id));
        }
    }
}

class DeliverWebhookJob implements ShouldQueue {
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public int $tries = 1; // retry-логика управляется вручную
    public int $timeout = 30;

    public function handle(WebhookDeliveryService $service): void {
        $delivery = WebhookDelivery::with('endpoint')->find($this->deliveryId);
        if (!$delivery || $delivery->status === 'delivered') return;

        $endpoint = $delivery->endpoint;
        $attempt = $delivery->attempt_count + 1;

        $body = json_encode([
            'id' => $delivery->event_id,
            'type' => $delivery->event_type,
            'created_at' => $delivery->created_at->toIso8601String(),
            'data' => $delivery->payload,
        ]);

        // HMAC-подпись
        $signature = 'sha256=' . hash_hmac('sha256', $body, $endpoint->secret);

        $startTime = microtime(true);
        try {
            $response = Http::timeout($endpoint->timeout_ms / 1000)
                ->withHeaders([
                    'Content-Type' => 'application/json',
                    'X-Webhook-ID' => $delivery->id,
                    'X-Webhook-Event' => $delivery->event_type,
                    'X-Webhook-Signature-256' => $signature,
                    'User-Agent' => 'YourApp-Webhooks/1.0',
                ])
                ->post($endpoint->url, json_decode($body, true));

            $elapsed = (int)((microtime(true) - $startTime) * 1000);
            $this->recordAttempt($delivery, $attempt, $response->status(), $body, $response->body(), $elapsed);

            if ($response->successful()) {
                $delivery->update([
                    'status' => 'delivered',
                    'delivered_at' => now(),
                    'last_http_status' => $response->status(),
                    'last_request_ms' => $elapsed,
                    'attempt_count' => $attempt,
                ]);
            } else {
                $this->scheduleRetry($delivery, $attempt, $endpoint, "HTTP {$response->status()}");
            }
        } catch (\Exception $e) {
            $elapsed = (int)((microtime(true) - $startTime) * 1000);
            $this->recordAttempt($delivery, $attempt, null, $body, null, $elapsed, $e->getMessage());
            $this->scheduleRetry($delivery, $attempt, $endpoint, $e->getMessage());
        }
    }

    private function scheduleRetry(WebhookDelivery $delivery, int $attempt, WebhookEndpoint $endpoint, string $error): void {
        if ($attempt >= $endpoint->max_retries) {
            $delivery->update(['status' => 'failed', 'last_error_message' => $error]);
            return;
        }

        // Exponential backoff: 5s, 25s, 125s, 625s, 3125s
        $delaySeconds = 5 ** $attempt;
        $nextRetryAt = now()->addSeconds($delaySeconds);

        $delivery->update([
            'status' => 'retrying',
            'attempt_count' => $attempt,
            'next_retry_at' => $nextRetryAt,
            'last_error_message' => $error,
        ]);

        dispatch(new DeliverWebhookJob($delivery->id))->delay($nextRetryAt);
    }
}

API של לוח הבקרה האדמיניסטרטיבי

// Получение списка endpoints с агрегированной статистикой
public function endpoints(Request $request): JsonResponse
{
    $endpoints = WebhookEndpoint::withCount([
        'deliveries as pending_count' => fn($q) => $q->where('status', 'pending'),
        'deliveries as failed_count' => fn($q) => $q->where('status', 'failed'),
        'deliveries as delivered_count' => fn($q) => $q->where('status', 'delivered'),
    ])
    ->orderByDesc('created_at')
    ->paginate(20);

    return response()->json($endpoints);
}

// Детальный лог доставок с фильтрацией
public function deliveries(Request $request, int $endpointId): JsonResponse
{
    $deliveries = WebhookDelivery::where('endpoint_id', $endpointId)
        ->when($request->status, fn($q) => $q->where('status', $request->status))
        ->when($request->event_type, fn($q) => $q->where('event_type', $request->event_type))
        ->with('attempts')
        ->orderByDesc('created_at')
        ->paginate(50);

    return response()->json($deliveries);
}

// Ручной ретрай конкретной доставки
public function retry(int $deliveryId): JsonResponse
{
    $delivery = WebhookDelivery::findOrFail($deliveryId);
    $delivery->update(['status' => 'pending', 'next_retry_at' => null]);
    dispatch(new DeliverWebhookJob($deliveryId));

    return response()->json(['queued' => true]);
}

// Тестовый webhook (ping)
public function ping(int $endpointId): JsonResponse
{
    $endpoint = WebhookEndpoint::findOrFail($endpointId);
    $this->webhookService->dispatch('webhook.ping', uniqid('ping_'), [
        'message' => 'Test webhook from dashboard',
        'timestamp' => now()->toIso8601String(),
    ]);

    return response()->json(['sent' => true]);
}

אימות חתימה בצד הנמען

// Node.js — получатель верифицирует HMAC-подпись
const crypto = require('crypto');

function verifyWebhookSignature(rawBody, signature, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(rawBody, 'utf8')
    .digest('hex');

  // Timing-safe сравнение — защита от timing attacks
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

app.post('/webhooks/yourapp', express.raw({type: 'application/json'}), (req, res) => {
  const signature = req.headers['x-webhook-signature-256'];

  if (!verifyWebhookSignature(req.body, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(req.body);

  // Отвечаем 200 сразу, обработку делаем асинхронно
  res.status(200).send('OK');
  processEventAsync(event);
});

ציר זמן

יום 1 — סכמת DB, DeliveryService בסיסי עם חתימת HMAC, Job עם לוגיקת ניסיונות חוזרים. יום 2 — REST API לממשק הניהול: נקודות קצה CRUD, לוג אספקה מסונן, ניסיון חוזר ידני.

יום 3 — ממשק ניהול Frontend (טבלת נקודות קצה, לוג אספקה עם drill-down לגוף בקשה/תגובה), ping לבדיקה, ניטור ספירות נכשל/ממתין.

שלבי פיתוח

שלב משך תוצאה
ניתוח ועיצוב 2–3 ימים מפרט טכני לסכמת DB ו-API
Backend: אספקה ו-API 5–7 ימים DeliveryService, Jobs, REST API
Frontend: ממשק ניהול 4–6 ימים ממשק ניהול וניטור
בדיקות והשקה 2–3 ימים Staging + production, הדרכת צוות

מה כלול

  • סכמת DB עם migrations ואינדקסים
  • שירות אספקה עם חתימת HMAC ו-backoff אקספוננציאלי
  • REST API לניהול מנויים וצפייה בלוגים
  • ממשק ניהול (React/Vue) עם סינון ו-drill-down
  • ניטור והתראות כאשר חריג סף שגיאות
  • תיעוד API (Swagger/OpenAPI)
  • השקה לשרת שלכם או לענן

תוצאות והבטחות

הניסיון שלנו: למעלה מ-5 שנים באינטגרציית מיקרוסרוויסים, יותר מ-50 פרויקטי webhook מוצלחים. אנו מבטיחים פעולה יציבה תחת עומס גבוה. מקצר את זמן חיפוש השגיאות ב-40% וחוסך עד 30% מתקציב התמיכה.

אם אתם רוצים שליטה מלאה על ה-webhooks שלכם — הזמינו פיתוח לוח בקרה. צרו קשר כדי לדון בפרויקט שלכם. קבלו ייעוץ והערכת לוח זמנים.