<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: yash ammanavar</title>
    <description>The latest articles on Forem by yash ammanavar (@yash_ammanavar_).</description>
    <link>https://forem.com/yash_ammanavar_</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3882050%2Fc891a1c3-bb30-43cb-9599-4f9495eb12bf.png</url>
      <title>Forem: yash ammanavar</title>
      <link>https://forem.com/yash_ammanavar_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/yash_ammanavar_"/>
    <language>en</language>
    <item>
      <title>Building an Event‑Driven System in Go Using Kafka</title>
      <dc:creator>yash ammanavar</dc:creator>
      <pubDate>Thu, 16 Apr 2026 09:12:54 +0000</pubDate>
      <link>https://forem.com/yash_ammanavar_/building-an-event-driven-system-in-go-using-kafka-3p1h</link>
      <guid>https://forem.com/yash_ammanavar_/building-an-event-driven-system-in-go-using-kafka-3p1h</guid>
      <description>&lt;p&gt;A practical guide for backend engineers&lt;br&gt;
Event‑driven architecture (EDA) has become a cornerstone of modern distributed systems. Whether you’re building microservices, real‑time analytics, or scalable data pipelines, events help you decouple services, scale independently, and react to changes in real time.&lt;br&gt;
In this blog, we’ll walk through how to design and build an event‑driven system using Go and Apache Kafka, with clear concepts, architecture decisions, and real code examples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. What Is an Event‑Driven System?&lt;/strong&gt;&lt;br&gt;
In an event‑driven system:&lt;/p&gt;

&lt;p&gt;Producers emit events when something happens&lt;br&gt;
Brokers (like Kafka) persist and distribute those events&lt;br&gt;
Consumers react to events asynchronously&lt;/p&gt;

&lt;p&gt;Instead of services calling each other directly (request/response), services communicate by publishing events.&lt;br&gt;
Example events:&lt;/p&gt;

&lt;p&gt;OrderCreated&lt;br&gt;
PaymentProcessed&lt;br&gt;
BidSubmitted&lt;br&gt;
ReportGenerated&lt;/p&gt;

&lt;p&gt;This pattern leads to:&lt;/p&gt;

&lt;p&gt;Loose coupling&lt;br&gt;
Better scalability&lt;br&gt;
Clear separation of responsibilities&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Why Kafka + Go?&lt;/strong&gt;&lt;br&gt;
Why Kafka?&lt;br&gt;
Apache Kafka is a distributed event streaming platform that provides:&lt;/p&gt;

&lt;p&gt;High throughput&lt;br&gt;
Durability (events are persisted)&lt;br&gt;
Replayability&lt;br&gt;
Strong ordering guarantees within partitions&lt;/p&gt;

&lt;p&gt;Kafka is ideal when:&lt;/p&gt;

&lt;p&gt;You need reliable event delivery&lt;br&gt;
Consumers need to replay history&lt;br&gt;
Systems must scale horizontally&lt;/p&gt;

&lt;p&gt;Why Go?&lt;br&gt;
Go is an excellent fit for event‑driven systems because:&lt;/p&gt;

&lt;p&gt;It’s fast and lightweight&lt;br&gt;
Concurrency with goroutines is simple&lt;br&gt;
Binaries are small and easy to deploy&lt;br&gt;
Strong ecosystem for networking and streaming&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. High‑Level Architecture&lt;/strong&gt;&lt;br&gt;
Let’s start with a simple architecture:&lt;br&gt;
+-------------+        +------------+        +----------------+&lt;br&gt;
|   Producer  | -----&amp;gt; |   Kafka    | -----&amp;gt; |   Consumer(s)  |&lt;br&gt;
|  (Go App)   |        |   Topic    |        |   (Go Apps)    |&lt;br&gt;
+-------------+        +------------+        +----------------+&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Choosing a Kafka Client for Go&lt;/strong&gt;&lt;br&gt;
Popular Kafka libraries for Go:&lt;/p&gt;

&lt;p&gt;confluent‑kafka‑go → High performance (librdkafka based)&lt;br&gt;
sarama → Pure Go, very popular&lt;br&gt;
segmentio/kafka‑go → Simple API, Go‑native&lt;/p&gt;

&lt;p&gt;For clarity and simplicity, we’ll use kafka-go.&lt;br&gt;
Install it:&lt;/p&gt;

&lt;p&gt;go get github.com/segmentio/kafka-go&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Designing the Event Model&lt;/strong&gt;&lt;br&gt;
Events should be:&lt;/p&gt;

&lt;p&gt;Immutable&lt;br&gt;
Self‑describing&lt;br&gt;
Versioned&lt;/p&gt;

&lt;p&gt;Example Event (JSON)&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "event_type": "OrderCreated",&lt;br&gt;
  "event_version": 1,&lt;br&gt;
  "event_id": "c8b9c2e1-22a4-4b63-8c34-4ccf4f7f90aa",&lt;br&gt;
  "timestamp": "2026-04-16T10:30:00Z",&lt;br&gt;
  "payload": {&lt;br&gt;
    "order_id": "ORD-123",&lt;br&gt;
    "user_id": "USR-456",&lt;br&gt;
    "amount": 1499.99&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Writing a Kafka Producer in Go&lt;/strong&gt;&lt;br&gt;
A producer emits events when something meaningful happens.&lt;br&gt;
Producer Example&lt;/p&gt;

&lt;p&gt;writer := kafka.NewWriter(kafka.WriterConfig{&lt;br&gt;
    Brokers:  []string{"localhost:9092"},&lt;br&gt;
    Topic:    "orders",&lt;br&gt;
    Balancer: kafka.LeastBytes,&lt;br&gt;
})&lt;/p&gt;

&lt;p&gt;event := []byte(&lt;code&gt;{&lt;br&gt;
  "event_type": "OrderCreated",&lt;br&gt;
  "event_version": 1,&lt;br&gt;
  "order_id": "ORD-123",&lt;br&gt;
  "amount": 1499.99&lt;br&gt;
}&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;err := writer.WriteMessages(context.Background(),&lt;br&gt;
    kafka.Message{&lt;br&gt;
        Key:   []byte("ORD-123"),&lt;br&gt;
        Value: event,&lt;br&gt;
    },&lt;br&gt;
)&lt;br&gt;
if err != nil {&lt;br&gt;
    log.Fatal("failed to write message:", err)&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Key Points&lt;/p&gt;

&lt;p&gt;Use a key to ensure ordering (same key → same partition)&lt;br&gt;
Make producers idempotent if possible&lt;br&gt;
Emit events after a successful state change&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Writing a Kafka Consumer in Go&lt;/strong&gt;&lt;br&gt;
Consumers react to events and perform side effects.&lt;/p&gt;

&lt;p&gt;Consumer Example&lt;/p&gt;

&lt;p&gt;reader := kafka.NewReader(kafka.ReaderConfig{&lt;br&gt;
    Brokers: []string{"localhost:9092"},&lt;br&gt;
    Topic:   "orders",&lt;br&gt;
    GroupID: "order-processors",&lt;br&gt;
})&lt;/p&gt;

&lt;p&gt;for {&lt;br&gt;
    msg, err := reader.ReadMessage(context.Background())&lt;br&gt;
    if err != nil {&lt;br&gt;
        log.Println("error reading message:", err)&lt;br&gt;
        continue&lt;br&gt;
    }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;log.Printf("Processing event: %s\n", string(msg.Value))

// Process the event
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;Consumer Groups&lt;/p&gt;

&lt;p&gt;Kafka distributes partitions across consumers&lt;br&gt;
Each message is processed once per group&lt;br&gt;
You can scale horizontally by adding consumers&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Handling Failures &amp;amp; Retries&lt;/strong&gt;&lt;br&gt;
Failures will happen.&lt;br&gt;
Best Practices&lt;br&gt;
 Make consumers idempotent&lt;br&gt;
 Retry transient failures&lt;br&gt;
 Send poison messages to a DLQ (Dead Letter Topic)&lt;br&gt;
 Commit offsets after successful processing&lt;br&gt;
Pattern:&lt;/p&gt;

&lt;p&gt;Read event&lt;br&gt;
Process&lt;br&gt;
On success → commit offset&lt;br&gt;
On failure → retry or move to DLQ&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Event‑Driven vs Request‑Driven&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Request/Response&lt;/th&gt;
&lt;th&gt;Event‑Driven&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Coupling&lt;/td&gt;
&lt;td&gt;Tight&lt;/td&gt;
&lt;td&gt;Loose&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalability&lt;/td&gt;
&lt;td&gt;Harder&lt;/td&gt;
&lt;td&gt;Easier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;Immediate&lt;/td&gt;
&lt;td&gt;Asynchronous&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resilience&lt;/td&gt;
&lt;td&gt;Lower&lt;/td&gt;
&lt;td&gt;Higher&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;10. Common Mistakes to Avoid&lt;/strong&gt;&lt;br&gt;
 Treating Kafka like a message queue&lt;br&gt;
 Putting business logic in producers&lt;br&gt;
 Publishing database‑shaped events&lt;br&gt;
 Ignoring schema evolution&lt;br&gt;
 Blocking consumers with slow processing&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;11. When Event‑Driven Architecture Makes Sense&lt;/strong&gt;&lt;br&gt;
EDA is a great fit when:&lt;/p&gt;

&lt;p&gt;Multiple systems react to the same event&lt;br&gt;
You need auditability and replay&lt;br&gt;
You expect growth and change&lt;br&gt;
Near real‑time processing is required&lt;/p&gt;

&lt;p&gt;It’s not ideal for:&lt;/p&gt;

&lt;p&gt;Simple CRUD apps&lt;br&gt;
Strict request/response workflows&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12. Final Thoughts&lt;/strong&gt;&lt;br&gt;
Go + Kafka is a powerful combination for building scalable, resilient, event‑driven systems.&lt;br&gt;
Start small:&lt;/p&gt;

&lt;p&gt;One topic&lt;br&gt;
One producer&lt;br&gt;
One consumer&lt;/p&gt;

&lt;p&gt;Then evolve:&lt;/p&gt;

&lt;p&gt;Add schemas (Avro/Protobuf)&lt;br&gt;
Add retries and DLQs&lt;br&gt;
Add observability and metrics&lt;/p&gt;

&lt;p&gt;Event‑driven systems reward good design upfront, but they scale beautifully when done right.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>backend</category>
      <category>go</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
