# Alert Service — Redis + התראות סף📖 שיעור

## מה זה?

Analyzer עלול לזהות **את אותה** אנומליה כמה פעמים ברציפות (אם הערך החריג נשאר חריג לאורך כמה אירועים רצופים) — בלי הגנה, Alert Service היה שולח 10 התראות זהות למישהו, מטריד ומיותר. Redis (מיחידת NoSQL) פותר את זה: שומר "כבר התרענו על זה" עם TTL — אם אותה אנומליה מתגלה שוב תוך זמן קצר, לא שולחים התראה כפולה.

## מילות מפתח שחשוב לזכור

• Deduplication (מניעת כפילות) — זיהוי שהתראה "כבר נשלחה" ומניעת שליחה חוזרת מיותרת

• Threshold Alert — התראה שנשלחת רק כשערך חוצה סף מוגדר מראש, לא על כל חריגה קטנה

• Alert Fatigue — תופעה אמיתית שבה יותר מדי התראות (כולל כפולות) גורמות למי שמקבל אותן להתעלם מכולן, כולל האמיתיות

```csharp
// AlertService — consumes from Kafka, Deduplication with Redis
public class AlertConsumerService : BackgroundService
{
    private readonly IDatabase _redis;   // from the NoSQL unit

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        using var consumer = new ConsumerBuilder<Null, string>(config).Build();
        consumer.Subscribe("anomaly-detected");   // matches the Contract from Analyzer

        while (!stoppingToken.IsCancellationRequested)
        {
            var result = consumer.Consume(stoppingToken);
            var finding = JsonSerializer.Deserialize<AnomalyFinding>(result.Message.Value);

            string dedupeKey = $"alert:{finding.EventId}";
            bool alreadyAlerted = await _redis.KeyExistsAsync(dedupeKey);   // cache check, like Cache-Aside

            if (!alreadyAlerted)
            {
                await SendAlert(finding);
                await _redis.StringSetAsync(dedupeKey, "sent", TimeSpan.FromMinutes(10));   // TTL — don't send again for 10 minutes
            }
        }
    }

    private Task SendAlert(AnomalyFinding finding)
    {
        Console.WriteLine($"🚨 Alert: event {finding.EventId} exceeded the expected range!");
        return Task.CompletedTask;
    }
}
```

## הסבר עיקרי

`BackgroundService` — Consumer שרץ ברציפות, לא endpoint — בניגוד ל-Collector (שיש לו endpoint שמישהו קורא אליו), Alert Service **מאזין** ברציפות ברקע לכל אורך חיי האפליקציה — `BackgroundService` הוא הדפוס הסטנדרטי ב-ASP.NET Core לקוד שרץ ברקע (לא תגובה לבקשת HTTP ספציפית).

Deduplication עם Redis הוא Cache-Aside בהיפוך תפקידים — בשיעור Redis (מיחידת NoSQL) בדקנו "האם יש במטמון?" כדי **לקצר** תהליך; כאן בודקים "האם כבר שלחתי?" כדי **למנוע** פעולה כפולה. אותו כלי בדיוק (`KeyExistsAsync`+TTL), שימוש הפוך: לא חוסכים חישוב, מונעים חזרתיות מיותרת.

Threshold, לא כל חריגה — Analyzer כבר "סינן" חריגות (2 סטיות תקן), אבל Alert Service יכול להוסיף שכבת סף נוספת משלו — למשל, להתריע רק אם חריגה חוזרת **3 פעמים** תוך דקה, לא על חריגה בודדת. זה מונע Alert Fatigue — יותר מדי התראות "אמיתיות אך לא-קריטיות" שגורמות למי שמקבל אותן להתעלם מהכל, כולל האמיתי-חשוב.

## יתרונות

Redis Deduplication מונע הצפת התראות זהות; `BackgroundService` נותן דפוס נקי לצריכה רציפה ברקע; שכבת Threshold נוספת מפחיתה Alert Fatigue.

## חסרונות

TTL קבוע מדי (10 דקות בדוגמה) עלול להחמיץ הידרדרות אמיתית שממשיכה מעבר לחלון הזה; אם Redis לא זמין, Deduplication נכשל בשקט (או חוסם התראות לגמרי, תלוי במימוש) — נדרש טיפול שגיאות מפורש.

## נקודות חשובות

• Deduplication מונע התראות כפולות על אותו אירוע תוך זמן קצר, עם Redis+TTL

• `BackgroundService` הוא הדפוס הסטנדרטי לצריכת Kafka רציפה ב-ASP.NET Core

• Alert Fatigue הוא סיכון אמיתי — יותר מדי התראות (גם אמיתיות) פוגעות באפקטיביות שלהן

• זהו אותו מנגנון Cache-Aside מיחידת Redis, בשימוש הפוך (מניעת חזרה, לא חיסכון חישוב)

## טעויות נפוצות

• לשלוח התראה על כל הודעת אנומליה בלי Deduplication — הצפה מהירה של אותה בעיה שוב ושוב

• לבחור TTL קצר/ארוך מדי בלי לחשוב על טבע הבעיה שמנטרים

• לא לטפל בכישלון Redis (חיבור נכשל) — עלול לחסום כל התראה עתידית או להציף בלי הגנה, תלוי בכיוון הכישלון

## סיכום

Alert Service צורך ממצאי אנומליה מ-`anomaly-detected` (תואם ל-Contract מ-Analyzer) דרך `BackgroundService`, ומשתמש ב-Redis Deduplication (`KeyExistsAsync`+TTL) כדי למנוע התראות כפולות על אותה בעיה תוך זמן קצר — אותו מנגנון Cache-Aside מיחידת Redis, בכיוון הפוך. שכבת Threshold נוספת יכולה למנוע Alert Fatigue — יותר מדי התראות שגורמות להתעלמות מהאמיתיות.

## דוקומנטציה רשמית

[Microsoft Learn — BackgroundService](https://learn.microsoft.com/dotnet/core/extensions/workers)

---

## תרגילים

### תרגיל 1 — Deduplication בסיסי

**המשימה:** כתבו פונקציה `bool ShouldAlert(string key)` שבודקת Redis, ומחזירה `true` פעם ראשונה בלבד לכל `key` תוך TTL של דקה.

**בדיקה:** קריאה ראשונה מחזירה `true`; קריאה שנייה תוך פחות מדקה על אותו `key` מחזירה `false`; אחרי דקה, `true` שוב.

### תרגיל 2 — BackgroundService מינימלי

**המשימה:** כתבו `BackgroundService` שמדפיס "בדיקה..." כל 5 שניות (בלי Kafka עדיין), והריצו אותו כחלק מ-ASP.NET Core app.

**בדיקה:** ההודעה מודפסת ברציפות ברקע, גם בלי בקשת HTTP נכנסת כלשהי.

---

## פרויקט מסכם

**המשימה:** ממשו את Alert Service המלא לפי ה-Contract שהצוות כתב.

**דרישות:**
1. `BackgroundService` שצורך מ-`anomaly-detected`
2. Deduplication עם Redis, TTL סביר (5-10 דקות)
3. הדפסת/רישום התראה ברורה עם פרטי האירוע (לא רק "יש בעיה")

**בדיקה:** שליחת אותה אנומליה כמה פעמים ברצף (דרך Collector+Analyzer) מייצרת התראה אחת בלבד; אחרי TTL, אותה אנומליה בדיוק כן מייצרת התראה נוספת.

## מה בפרק הבא

בפרק הבא — **Dashboard Service**: השירות הרביעי והאחרון — מציג תמונת מצב מצטברת מכל שאר השירותים, בפייתון.
