# Kafka — Topics, Partitions ו-Consumer Groups📖 שיעור

## מה זה?

שירות "הזמנות" צריך להודיע לשירות "מלאי" ולשירות "התראות" שהזמנה חדשה נוצרה. קריאת HTTP ישירה (מיחידת ASP.NET Core) הייתה עובדת — אבל אז שירות ההזמנות **תלוי** בזמינות שני השירותים האחרים באותו רגע, וצריך לחכות לתשובה משניהם. Kafka פותר את זה: שירות ההזמנות "מפרסם" הודעה **פעם אחת**, וכל שירות שמעוניין "מאזין" לה בזמנו שלו — תקשורת אסינכרונית, בלי תלות ישירה בין הצדדים.

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

• Topic — "ערוץ" בעל שם ב-Kafka שהודעות נשלחות אליו (למשל `order-created`)

• Producer — שירות ששולח (מפרסם) הודעות לTopic

• Consumer — שירות שקורא (צורך) הודעות מ-Topic

• Partition — Topic מחולק פנימית לכמה חלקים, מאפשר עיבוד מקבילי ומהיר יותר

• Offset — "סמן מיקום" שכל Consumer שומר — עד איזו הודעה בTopic הוא כבר קרא

• Consumer Group — קבוצת Consumers ששולחים ביחד הודעות מTopic, כל הודעה מטופלת פעם אחת בקבוצה (לא כל Consumer מקבל הכל)

```mermaid
flowchart RL
    P["Order Service<br/>(Producer)"] -->|"publish message"| T["Topic:<br/>order-created"]
    T --> C1["Inventory Service<br/>(Consumer)"]
    T --> C2["Notification Service<br/>(Consumer)"]
```

```csharp
// Producer — publish a message, doesn't wait for a response from anyone
using var producer = new ProducerBuilder<Null, string>(config).Build();

var order = new { OrderId = 123, CustomerId = 5, Total = 250 };
string json = JsonSerializer.Serialize(order);   // JSON, from the previous unit

await producer.ProduceAsync("order-created", new Message<Null, string> { Value = json });
// That's it — the Order Service moves on, without waiting for anyone to process the message
```

```csharp
// Consumer — listens and processes messages on its own time
using var consumer = new ConsumerBuilder<Null, string>(config).Build();
consumer.Subscribe("order-created");

while (true)
{
    var result = consumer.Consume();   // waits for the next message
    var order = JsonSerializer.Deserialize<Order>(result.Message.Value);
    Console.WriteLine($"Updating inventory for order {order.OrderId}");
}
```

## הסבר עיקרי

Producer/Consumer לא "מדברים" ישירות זה עם זה — Producer שולח ל-Topic ולא יודע (ולא צריך לדעת) מי, אם בכלל, מאזין אליו. Consumer קורא מ-Topic בזמנו שלו, גם אם ה-Producer כבר "עבר הלאה" מזמן. זה שונה מהותית מ-HTTP (מיחידת ASP.NET Core) שבו הלקוח **ממתין** לתשובה — כאן, "שליחה" ו"עיבוד" מנותקים לגמרי בזמן.

Partition מאפשר מקביליות — Topic עם 3 Partitions יכול "לשרת" 3 Consumers שונים בו-זמנית (כל אחד קורא Partition אחר), מעבד הודעות מהר יותר מ-Consumer בודד. Offset הוא איך כל Consumer "זוכר" איפה הוא עצר — אם הוא קורס ועולה מחדש, הוא ממשיך מה-Offset האחרון שנשמר, לא מההתחלה.

Consumer Group מונע עיבוד כפול — אם יש 3 מופעים (Instances) של `Inventory Service` רצים במקביל (לביצועים/זמינות), רוצים שכל הודעה תטופל **פעם אחת בלבד**, לא 3 פעמים. Consumer Group עושה בדיוק את זה: כל ההודעות ב-Topic מתחלקות בין חברי הקבוצה, כל הודעה מגיעה לחבר אחד בלבד בקבוצה.

## יתרונות

Kafka מנתק שירותים זה מזה בזמן (Decoupling) — Producer לא ממתין ל-Consumer; Partitions מאפשרות עיבוד מקבילי ומהיר; Consumer Groups מבטיחות שכל הודעה מטופלת פעם אחת גם עם כמה מופעי שירות רצים; Offset מאפשר להמשיך מאיפה שהפסיקו אחרי קריסה.

## חסרונות

תקשורת אסינכרונית קשה יותר לדבג מ-HTTP סינכרוני (אין "תשובה מיידית" לבדוק); Kafka דורש תשתית וניהול נוספים (Broker, ZooKeeper/KRaft); עיצוב נכון של Topics/Partitions דורש תכנון מראש.

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

• Producer שולח ל-Topic; Consumer קורא ממנו — לא מדברים ישירות זה עם זה

• Partition מאפשרת מקביליות; Offset הוא מיקום הקריאה של Consumer בתוך Partition

• Consumer Group מבטיח שכל הודעה מטופלת פעם אחת בקבוצה, גם עם כמה מופעי שירות

• Kafka מתאים לתקשורת אסינכרונית בין שירותים — לא תחליף ל-REST API סינכרוני בכל מקום

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

• לצפות שProducer "יידע" אם Consumer עיבד את ההודעה בהצלחה — הם מנותקים לגמרי בזמן

• לשים כמה מופעי שירות **לא** באותו Consumer Group, ולגלות שכל הודעה מטופלת כמה פעמים בטעות

• לבחור Kafka לתקשורת שדורשת תשובה מיידית (כמו "האם הכרטיס אושר?") — שם REST/HTTP סינכרוני מתאים יותר

## סיכום

Kafka מנתק שירותים בזמן — Producer מפרסם הודעה ל-Topic בלי להמתין, Consumer קורא ומעבד אותה בזמנו שלו. Partitions מאפשרות עיבוד מקבילי; Offset שומר מיקום קריאה שמאפשר המשכיות אחרי קריסה; Consumer Group מבטיח שכל הודעה מטופלת פעם אחת, גם עם כמה מופעי שירות. זהו הבסיס לתקשורת אסינכרונית בארכיטקטורת מיקרוסרביסים, שיחזור ביחידות הבאות של הקורס.

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

[Apache Kafka — Documentation](https://kafka.apache.org/documentation/)

[Confluent — .NET Client](https://docs.confluent.io/kafka-clients/dotnet/current/overview.html)

---

## תרגילים

### תרגיל 1 — Producer/Consumer בסיסי

**המשימה:** צרו Topic בשם `test-topic`, כתבו Producer ששולח 5 הודעות טקסט, וConsumer שקורא ומדפיס אותן.

**בדיקה:** כל 5 ההודעות מודפסות על ידי ה-Consumer, בסדר שנשלחו.

### תרגיל 2 — Consumer Group

**המשימה:** הריצו שני מופעי Consumer **באותה** Consumer Group על אותו Topic, ושלחו 10 הודעות. עקבו אילו הודעות כל מופע קיבל.

**בדיקה:** ביחד, שני המופעים מקבלים את כל 10 ההודעות בדיוק פעם אחת כל אחת — לא כפילות, לא החמצה.

---

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

**המשימה:** הוסיפו פרסום אירוע Kafka ל-`TasksController` (מהפרויקטים המסכמים) בכל יצירת משימה.

**דרישות:**
1. Topic `task-created` — כל `POST` מוצלח ל-`TasksController` מפרסם הודעת JSON עם פרטי המשימה
2. Consumer נפרד (קונסולה עצמאית, לא חלק מה-API) שמאזין ל-Topic ומדפיס "משימה חדשה נוצרה: [כותרת]"
3. הרצת ה-API והConsumer בו-זמנית — יצירת משימה דרך ה-API מופיעה בקונסולת ה-Consumer

**בדיקה:** יצירת משימה דרך endpoint ה-API גורמת מיד להדפסה בConsumer הנפרד, בלי שה-API ממתין לתגובה ממנו.

## מה בפרק הבא

בפרק הבא — **Kafka: Producer/Consumer מרובה-שפות**: שילוב C# ו-Python על אותו Topic — הוכחה שKafka לא תלוי בשפת התכנות, בדיוק כמו JSON.
