תיעדוף משימות בתור (Priority Queue)
תארו לעצמכם: 90% מהמשתמשים עוזבים את האתר שלכם אם אימייל איפוס הסיסמה לא מגיע תוך 5 שניות. אבל התור שלכם סתום בדוחות של 30 דקות. התוצאה — לקוחות אבודים ומשוב שלילי. נתקלנו בזה בפרויקט עם 150,000 משתמשים פעילים: משימות קריטיות (איפוס סיסמה, קודי SMS) היו באותו תור כמו ייצואים. לאחר יישום התעדוף, זמן ההמתנה למשימות קריטיות ירד מ-30 שניות ל-2 שניות — פי 15 מהר יותר. חיסכון בעלויות: התקנה מתחילה ב-500$, ולקוחות בדרך כלל רואים החזר השקעה תוך חודש. להלן איך אנחנו עושים זאת.
עם 5+ שנות ניסיון בעבודה עם תורים ולמעלה מ-50 פרויקטים, מסטארטאפים ועד ארגונים גדולים, הגישה שלנו היא לתכנן מודל עדיפויות, להגדיר עובדים (workers), ולהגן על המערכת מפני הרעבה (starvation). ללא הפשטות מיותרות, רק תבניות מוכחות.
למה תעדוף תורים הוא קריטי לביצועים?
ללא תעדוף, כל המשימות מעובדות בסדר FIFO. זה גורם לעיכובים בלתי מקובלים עבור פעולות קריטיות. לדוגמה, בפרויקט עם תעבורה גבוהה, כל 100ms של השהיה מפחיתים את ההמרה ב-7%. הלקוחות שלנו רואים ירידה של 80–95% בזמן התגובה למשימות קריטיות לאחר התעדוף. עובדים ייעודיים מבצעים פי 10 טוב יותר מעדיפות רכה (soft priority) תחת עומס גבוה.
מודל העדיפויות
חלוקה טיפוסית לשלוש רמות:
| תור | משימות | המתנה מקובלת |
|---|---|---|
critical |
איפוס סיסמה, קודי SMS, התראות תשלום | < 5 שניות |
default |
אימיילים טרנזקציוניים, התראות | < 30 שניות |
low |
דוחות, ייצואים, שליחות המוניות, אינדוקס | דקות/שעות |
בחירת הרמות תלויה ב-SLA העסקי שלכם. עבור חנות איקומרס, ייתכן שתרצו להוסיף תור high להזמנות. בסביבת ייצור, אנו שומרים על עומק תור קריטי מתחת ל-10, בעוד שהתור הנמוך יכול לגדול ל-5000 אך מעובד ברקע.
איך להגדיר עדיפויות ב-Laravel?
Laravel תומך בעדיפות רכה: העובד עובר על התורים בסדר שצוין. פקודה:
php artisan queue:work --queue=critical,default,low אם יש משימות ב-php artisan queue:work --queue=critical,default,low , העובד לא עובר ל-critical. העדיפות נקבעת בשליחת המשימה:
SendPasswordResetEmail::dispatch($user)->onQueue('critical'); או בתוך ה-Job דרך המאפיין default. זה פשוט ומהיר, אבל עם משימות ארוכות בתור הנמוך, משימות קריטיות עלולות להמתין. פתרון — עובדים ייעודיים של Horizon.
השוואה בין עדיפות רכה לעובדים ייעודיים
| פרמטר | עדיפות רכה | עובדים ייעודיים (Horizon) |
|---|---|---|
| השהיה לקריטי | יכולה להגיע לדקות | מובטחת < 5 שניות |
| תצורה | עובד אחד | מפקח (Supervisor) לכל תור |
| סיכון להרעבה | גבוה תחת עומס | מינימלי |
| משאבים | חסכוני יותר | דורש יותר תהליכים |
איך להשתמש בעובדים ייעודיים למשימות קריטיות?
Horizon מאפשר יצירת מאגרי עובדים נפרדים לכל תור. השוואה: עדיפות רכה — השהיה קריטית יכולה להגיע לדקות כשהתור הנמוך עמוס. עובדים ייעודיים מבטיחים < 5 שניות — פי 10 מהר יותר. דוגמת תצורה:
// config/horizon.php
'environments' => [
'production' => [
'critical-supervisor' => [
'connection' => 'redis',
'queue' => ['critical'],
'balance' => 'simple',
'minProcesses' => 2,
'maxProcesses' => 8,
'timeout' => 30,
],
'default-supervisor' => [
'connection' => 'redis',
'queue' => ['default'],
'balance' => 'auto',
'minProcesses' => 1,
'maxProcesses' => 5,
'timeout' => 60,
],
'low-supervisor' => [
'connection' => 'redis',
'queue' => ['low'],
'balance' => 'simple',
'processes' => 2,
'timeout' => 3600,
],
],
],כל מפקח עובד באופן עצמאי: קריטי לא חסום על ידי משימות נמוכות. זו תבנית סטנדרטית לפרויקטים עם תעבורה גבוהה.
מה זה הרעבה (Starvation) ואיך למנוע אותה?
הרעבה — משימות בעדיפות נמוכה אף פעם לא מעובדות בגלל זרם קבוע של משימות קריטיות. זה מוביל להצטברות אינסופית של דוחות וייצואים. שני פתרונות עיקריים:
הזדקנות (Aging) — הגדלת עדיפות לאורך זמן. יישום דרך משימה מתוזמנת:
// повышаем приоритет задач, ожидающих более 30 минут
Schedule::call(function () {
Job::where('queue', 'low')
->where('created_at', '<', now()->subMinutes(30))
->update(['queue' => 'default']);
})->everyFifteenMinutes();עובד ייעודי לנמוך — תהליך אחד מבטיח שמשימות נמוכות ירוצו בסופו של דבר. שילוב שתי השיטות נותן הגנה של 100%.
עדיפות דינמית מבוססת נתונים
ניתן להקצות עדיפות דינמית על סמך המשתמש. לדוגמה, לקוחות ארגוניים מקבלים עדיפות קריטית, משתמשים רגילים מקבלים ברירת מחדל. זה גמיש יותר מסכמה סטטית וחוסך משאבים.
עדיפות ב-BullMQ (Node.js)
BullMQ משתמש בעדיפויות מספריות דרך Redis Sorted Set. זה מדויק יותר מ-Laravel אך דורש תשתית נפרדת.
await queue.add('send-password-reset', { userId: 123 }, { priority: 1 });
await queue.add('generate-report', { reportId: 789 }, { priority: 10 });ככל שהמספר נמוך יותר, כך העדיפות גבוהה יותר. ב-Laravel זה פשוט יותר אם המחסנית שלכם כבר מבוססת PHP.
ניטור והתראות
עומק התור מנוטר דרך Redis: SendPasswordResetEmail::dispatch($user)->onQueue('critical'); . Horizon מציג זאת בלוח הבקרה שלו. אנו מגדירים התראות על גידול בתור — סימן לעובדים לא מספיקים. ספים מומלצים: אם $queue > 50, // config/horizon.php 'environments' => [ 'production' => [ 'critical-supervisor' => [ 'connection' => 'redis', 'queue' => ['critical'], 'balance' => 'simple', 'minProcesses' => 2, 'maxProcesses' => 8, 'timeout' => 30, ], 'default-supervisor' => [ 'connection' => 'redis', 'queue' => ['default'], 'balance' => 'auto', 'minProcesses' => 1, 'maxProcesses' => 5, 'timeout' => 60, ], 'low-supervisor' => [ 'connection' => 'redis', 'queue' => ['low'], 'balance' => 'simple', 'processes' => 2, 'timeout' => 3600, ], ], ], > 200, או // повышаем приоритет задач, ожидающих более 30 минут Schedule::call(function () { Job::where('queue', 'low') ->where('created_at', '<', now()->subMinutes(30)) ->update(['queue' => 'default']); })->everyFifteenMinutes(); > 1000 — התראה מיידית. זה מונע השבתות.
מה כלול
- בדיקת ארכיטקטורת התורים הנוכחית
- תכנון מודל עדיפויות עם SLA
- הגדרת עובדים (Horizon או BullMQ)
- מניעת הרעבה (הזדקנות + עובד ייעודי)
- ניטור ותיעוד ההתקנה
- גישה ללוחות ניטור
- הדרכת צוות (מפגש של שעתיים)
- 30 ימי תמיכה
ציר זמן: התקנה בסיסית של שלושה תורים — 3 עד 5 שעות. לוגיקת אנטי-הרעבה וניטור — 2 עד 4 שעות נוספות. העלות מחושבת באופן אישי החל מ-500$ להתקנה בסיסית.
קבלו פתרון מפתח ב-3–5 שעות—כתבו לנו להערכת מחסנית. הזמינו הגדרת תורים וקבלו ייעוץ למחסנית שלכם.
למידע נוסף על Laravel Horizon (תיעוד רשמי)







