מערכת Webhook עם לוגים וניסיונות חוזרים: התקנה סוהר

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

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

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

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

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
מערכת Webhook עם לוגים וניסיונות חוזרים: התקנה סוהר
בינוני
~2-3 ימים

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

שאלות נפוצות

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

  • פיתוח אפליקציית ווב עבור 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 עם תיעוד וניסיונות חוזרים: התקנה סוהר

השקתם אינטגרציה עם שותף CRM. האירועים הראשונים עוברים, אבל שעה לאחר מכן הלקוח מתלונן שחצי מההודעות מעולם לא התקבלו. היומנים שותקים — המקלט החזיר 200, אבל לא עיבד את הנתונים. ללא פרטים על כל ניסיון, גילוי הגורם הוא ניחוש. אנו בונים מערכות Webhook עם תיעוד מלא וניסיונות חוזרים: לא רק 'ירה ושכח', אלא שליטה על כל אירוע. 10+ שנים באינטגרציות B2B, 100+ פרויקטים — אנו מבטיחים שקיפות ואמינות.

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

למה תיעוד כל ניסיון הוא הבסיס למערכת webhook אמינה

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

אילו נתונים אנו מתעדים וכיצד זה מיושם

קבוצת נתונים מינימלית לכל ניסיון משלוח:

שדה תיאור
delivery_id UUID של המשלוח — מקשר את כל הניסיונות
attempt_number מספר ניסיון (1, 2, 3...)
started_at זמן התחלת הניסיון
duration_ms משך זמן — חשוב לזיהוי פסקי זמן
request_headers כותרות הבקשה (ללא סודות בטקסט פשוט)
request_body גוף הבקשה (מטען האירוע)
response_code סטטוס HTTP של התגובה
response_headers כותרות התגובה
response_body 2 KB הראשונים של גוף התגובה — לניפוי
error טקסט השגיאה ב-ConnectionException / Timeout

אנו מאחסנים ניסיונות בנפרד ממשלוחים — משלוח אחד יכול לכלול עד 8 ניסיונות. זה מאפשר צפייה בהיסטוריה המלאה והבנה באיזה שלב דברים השתבשו.

CREATE TABLE webhook_attempts (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    delivery_id UUID NOT NULL REFERENCES webhook_deliveries(id) ON DELETE CASCADE,
    attempt_number INTEGER NOT NULL,
    started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    duration_ms INTEGER,
    request_body JSONB,
    request_headers JSONB,
    response_code INTEGER,
    response_headers JSONB,
    response_body TEXT, -- обрезается до 2000 символов
    error_message TEXT,
    success BOOLEAN NOT NULL DEFAULT false
);
CREATE INDEX idx_attempts_delivery ON webhook_attempts(delivery_id);
CREATE INDEX idx_attempts_started ON webhook_attempts(started_at DESC);

יישום התיעוד:

class WebhookAttemptLogger {
    public function log( WebhookDelivery $delivery, int $attempt, WebhookAttemptData $data ): WebhookAttempt {
        return WebhookAttempt::create([
            'delivery_id' => $delivery->id,
            'attempt_number' => $attempt,
            'started_at' => $data->startedAt,
            'duration_ms' => $data->durationMs,
            'request_body' => $delivery->payload,
            'request_headers' => $data->requestHeaders,
            'response_code' => $data->responseCode,
            'response_headers' => $data->responseHeaders,
            'response_body' => $data->responseBody ? mb_substr($data->responseBody, 0, 2000) : null,
            'error_message' => $data->errorMessage,
            'success' => $data->success,
        ]);
    }
}

class SendWebhookJob implements ShouldQueue {
    public function handle( WebhookAttemptLogger $logger ): void {
        $startedAt = now();
        $requestHeaders = $this->buildHeaders();
        try {
            $response = Http::timeout(15)
                ->withHeaders($requestHeaders)
                ->post($this->delivery->subscription->endpoint_url, $this->delivery->payload);
            $durationMs = (int)(microtime(true) * 1000 - $startedAt->timestamp * 1000);
            $logger->log($this->delivery, $this->delivery->attempt_count, new WebhookAttemptData(
                startedAt: $startedAt,
                durationMs: $durationMs,
                requestHeaders: $requestHeaders,
                responseCode: $response->status(),
                responseHeaders: $response->headers(),
                responseBody: $response->body(),
                success: $response->successful(),
            ));
            if ($response->successful()) {
                $this->delivery->markDelivered();
            } else {
                $this->delivery->scheduleRetry();
            }
        } catch (\Throwable $e) {
            $durationMs = (int)(microtime(true) * 1000 - $startedAt->timestamp * 1000);
            $logger->log($this->delivery, $this->delivery->attempt_count, new WebhookAttemptData(
                startedAt: $startedAt,
                durationMs: $durationMs,
                requestHeaders: $requestHeaders,
                errorMessage: get_class($e) . ': ' . $e->getMessage(),
                success: false,
            ));
            $this->delivery->scheduleRetry();
        }
    }
}

כיצד מאורגן שליחה חוזרת ידנית

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

class WebhookDeliveryController extends Controller {
    // Повторить конкретную доставку
    public function resend(WebhookDelivery $delivery): JsonResponse {
        abort_if(
            $delivery->status === 'delivered',
            422,
            'Delivery already succeeded'
        );

        $delivery->update([
            'status' => 'pending',
            'attempt_count' => 0,
            'next_attempt_at' => now(),
        ]);

        SendWebhookJob::dispatch($delivery);

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

    // Повторить все упавшие доставки подписки
    public function resendFailed(WebhookSubscription $subscription): JsonResponse {
        $count = WebhookDelivery::where('subscription_id', $subscription->id)
            ->where('status', 'failed')
            ->count();

        WebhookDelivery::where('subscription_id', $subscription->id)
            ->where('status', 'failed')
            ->update([
                'status' => 'pending',
                'attempt_count' => 0,
                'next_attempt_at' => now(),
            ]);

        WebhookDelivery::where('subscription_id', $subscription->id)
            ->where('status', 'pending')
            ->each(fn($d) => SendWebhookJob::dispatch($d));

        return response()->json(['requeued' => $count]);
    }

    // История попыток для конкретной доставки
    public function attempts(WebhookDelivery $delivery): JsonResponse {
        return response()->json(
            $delivery->attempts()
                ->orderBy('attempt_number')
                ->get(['attempt_number', 'started_at', 'duration_ms', 'response_code', 'response_body', 'error_message', 'success'])
        );
    }
}

תוכנית יישום שלב אחר שלב למערכת webhook עם תיעוד

שלב תיאור משך זמן
ניתוח אינטגרציות קיימות זיהוי סוגי אירועים ומקלטים יום אחד
עיצוב סכמה טבלאות: webhook_subscriptions, webhook_deliveries, webhook_attempts יום אחד
יישום תיעוד מחלקת WebhookAttemptLogger והתאמות ל-SendWebhookJob יומיים
הגדרת מדיניות ניסיונות חוזרים מרווחים, מספר ניסיונות מקסימלי (אנו ממליצים על 5-8) יום אחד
יצירת לוח מחוונים סינון לפי סטטוס, סוג אירוע, תאריך. מצטברים: ספירה ב-24 שעות, זמן משלוח P95 יומיים
תיעוד API לשליחה חוזרת ידנית Swagger/OpenAPI יום אחד
בדיקות סימולציית כשלים באמצעות stubs יום אחד

אסטרטגיית שמירת יומנים: ניסיונות מוצלחים — 30 יום עם גוף, לאחר מכן רק מטא-דאטה. ניסיונות כושלים — 90 יום לביקורת. גוף תגובת שגיאה — מקסימום 2 KB, נתונים בינאריים אינם נשמרים.

למה המערכת שלנו חוסכת עד 80% מזמן הניפוי

קובץ יומן טיפוסי חסר הקשר: אתם רואים שגיאה אבל לא מה הוביל אליה. המערכת שלנו מאחסנת את הכרונולוגיה המלאה של כל משלוח, ומקשרת את כל הניסיונות. זה מקצר את זמן החקירה משעות לדקות. מצטברים מובנים (ממוצע ניסיונות, זמן משלוח P95) מאפשרים גילוי מוקדם של אינטגרציות בעייתיות. השוו: ללא תיעוד — חיפוש ידני ביומני שרת, ניחושים, הפעלה מחדש של אינטגרציות. עם המערכת שלנו — פתחו את לוח המחוונים, סננו לפי סטטוס, ראו את ההיסטוריה של כל ניסיון. לחצו על "שלח מחדש" ואירועים כושלים נכנסים שוב לתור. אנו מיישמים זאת על תורי Laravel עם PostgreSQL. התוצאה היא חיסכון של עד 80% בזמן הניפוי.

מה כלול וציר זמן

  • פיתוח מודול תיעוד ניסיונות ושליחה חוזרת
  • הגדרת תור ומדיניות ניסיונות חוזרים
  • יצירת לוח מחוונים עם סינון ומצטברים
  • תיעוד API וסכמת נתונים
  • הדרכת צוות על שימוש במערכת
  • חודש אחד של תמיכה טכנית

ציר זמן: מערכת תיעוד ניסיונות ושליחה חוזרת ידנית — 3 עד 5 ימים. עם לוח מחוונים, מצטברים, סינון ומדיניות שמירה — 1 עד 1.5 שבועות.

הזמינו מערכת סוהר — צרו קשר להערכה מדויקת של הפרויקט שלכם. קבלו ייעוץ על היישום.