<?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>DEV Community: Geetansh Garg</title>
    <description>The latest articles on DEV Community by Geetansh Garg (@geetnsh2k1).</description>
    <link>https://dev.to/geetnsh2k1</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%2F1477836%2F1232040d-df7b-471e-ae4e-91232ef3a052.png</url>
      <title>DEV Community: Geetansh Garg</title>
      <link>https://dev.to/geetnsh2k1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/geetnsh2k1"/>
    <language>en</language>
    <item>
      <title>🎯 Using Redis Streams Over Pub/Sub: A Practical Guide for Backend Engineers</title>
      <dc:creator>Geetansh Garg</dc:creator>
      <pubDate>Fri, 20 Jun 2025 11:09:50 +0000</pubDate>
      <link>https://dev.to/geetnsh2k1/using-redis-streams-over-pubsub-a-practical-guide-for-backend-engineers-5789</link>
      <guid>https://dev.to/geetnsh2k1/using-redis-streams-over-pubsub-a-practical-guide-for-backend-engineers-5789</guid>
      <description>&lt;p&gt;Hey DEV Community! 👋&lt;br&gt;&lt;br&gt;
I'm &lt;strong&gt;Geetansh Garg&lt;/strong&gt;, a backend engineer who loves building real-time, scalable systems. In my previous post, I shared how we built a real-time notification service using FastAPI and Redis Streams.&lt;/p&gt;

&lt;p&gt;Today, I want to go deeper into &lt;strong&gt;why we moved from Redis Pub/Sub to Redis Streams&lt;/strong&gt; — and why this shift made our real-time infrastructure much more reliable and production-ready.&lt;/p&gt;


&lt;h2&gt;
  
  
  ❓ Why Redis Pub/Sub Didn't Work for Us
&lt;/h2&gt;

&lt;p&gt;We initially chose Redis Pub/Sub because it was simple to implement and worked well in early testing. But as the system grew, we hit several limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ &lt;strong&gt;Message loss&lt;/strong&gt;: If a user wasn't connected when the message was published, it was gone forever.&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;No persistence&lt;/strong&gt;: Pub/Sub doesn’t store message history.&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;No retries or acknowledgment&lt;/strong&gt;: We couldn’t confirm message delivery.&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;Hard to scale&lt;/strong&gt;: Horizontal scaling of consumers was error-prone and lacked coordination.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, &lt;strong&gt;Pub/Sub is great for fire-and-forget messages&lt;/strong&gt;, but &lt;strong&gt;not suitable when reliability matters&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  ✅ Why Redis Streams Was a Better Fit
&lt;/h2&gt;

&lt;p&gt;We explored alternatives and landed on &lt;strong&gt;Redis Streams&lt;/strong&gt;, which offered exactly what we needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Durability&lt;/strong&gt;: Messages are stored until consumed.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Consumer Groups&lt;/strong&gt;: Support for multiple parallel consumers with coordinated delivery.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Acknowledgement&lt;/strong&gt;: Messages are marked delivered only after explicit acknowledgment.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Replayability&lt;/strong&gt;: Consumers can resume from the last processed ID.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These features helped us build a &lt;strong&gt;fault-tolerant, reliable real-time pipeline&lt;/strong&gt; for notifications, especially for users who might be temporarily offline.&lt;/p&gt;


&lt;h2&gt;
  
  
  ⚙️ Sample Code: Redis Streams in Action
&lt;/h2&gt;

&lt;p&gt;Here’s how we use Redis Streams for our notification service:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Pushing a notification to the stream:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xadd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;notifications_stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You’ve got a new alert&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lang&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;priority&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Reading from the stream as a consumer:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xreadgroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;groupname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;notifier_group&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;consumername&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;worker-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;streams&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;notifications_stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Acknowledging processed messages:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;notifications_stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;notifier_group&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also set up logic to retry unacknowledged messages using XPENDING and XCLAIM.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Lessons Learned
&lt;/h2&gt;

&lt;p&gt;Redis Streams was a game-changer for our use case, allowing us to &lt;strong&gt;scale safely&lt;/strong&gt; and &lt;strong&gt;avoid message loss&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We added a background task to periodically trim the stream using &lt;code&gt;XTRIM&lt;/code&gt; to keep memory usage in check.&lt;/li&gt;
&lt;li&gt;Creating a &lt;strong&gt;resumable consumer logic&lt;/strong&gt; gave us high availability even during service restarts.&lt;/li&gt;
&lt;li&gt;Implementing a &lt;strong&gt;WebSocket layer&lt;/strong&gt; on top helped us push these events live to users with &lt;strong&gt;JWT-secured sessions&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛠️ When NOT to Use Redis Streams
&lt;/h2&gt;

&lt;p&gt;Redis Streams isn’t the perfect fit for all cases. You might not want to use it when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⚡ You need &lt;strong&gt;ultra-low latency fire-and-forget messaging&lt;/strong&gt; (Pub/Sub is simpler here).&lt;/li&gt;
&lt;li&gt;🌀 Your system has &lt;strong&gt;complex message routing or massive scale&lt;/strong&gt; — in that case, &lt;strong&gt;Kafka&lt;/strong&gt; might be a better tool.&lt;/li&gt;
&lt;li&gt;🔍 You &lt;strong&gt;don’t need history or delivery guarantees&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔚 Final Takeaway
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Redis Streams&lt;/strong&gt; gave us exactly what we needed — a &lt;strong&gt;scalable&lt;/strong&gt;, &lt;strong&gt;reliable&lt;/strong&gt;, and &lt;strong&gt;production-friendly&lt;/strong&gt; way to deliver real-time notifications with &lt;strong&gt;FastAPI and WebSockets&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you're building something similar, I highly recommend giving Redis Streams a serious look — especially if you're struggling with Pub/Sub limitations.&lt;/p&gt;




&lt;h2&gt;
  
  
  💬 Let’s Talk!
&lt;/h2&gt;

&lt;p&gt;Have you worked with Redis Streams or built similar systems?&lt;/p&gt;

&lt;p&gt;Would love to hear how you tackled &lt;strong&gt;durability&lt;/strong&gt;, &lt;strong&gt;replay&lt;/strong&gt;, or &lt;strong&gt;scale challenges&lt;/strong&gt;!&lt;br&gt;&lt;br&gt;
Drop a comment or DM — always happy to nerd out on system design 😄&lt;/p&gt;

</description>
    </item>
    <item>
      <title>🚀 Building a Real-Time Notification Service with FastAPI, Redis Streams, and WebSockets</title>
      <dc:creator>Geetansh Garg</dc:creator>
      <pubDate>Fri, 20 Jun 2025 10:47:28 +0000</pubDate>
      <link>https://dev.to/geetnsh2k1/building-a-real-time-notification-service-with-fastapi-redis-streams-and-websockets-52ib</link>
      <guid>https://dev.to/geetnsh2k1/building-a-real-time-notification-service-with-fastapi-redis-streams-and-websockets-52ib</guid>
      <description>&lt;p&gt;Hi DEV Community! 👋&lt;br&gt;&lt;br&gt;
I'm &lt;strong&gt;Geetansh Garg&lt;/strong&gt;, a Senior Software Engineer passionate about &lt;strong&gt;scalable backend systems&lt;/strong&gt;, &lt;strong&gt;clean architecture&lt;/strong&gt;, and &lt;strong&gt;real-world problem solving&lt;/strong&gt;. This is my first post here, and I wanted to kick things off by sharing one of the most exciting problems I’ve been working on lately.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 The Problem
&lt;/h2&gt;

&lt;p&gt;We needed to deliver &lt;strong&gt;real-time notifications&lt;/strong&gt; to users in a FastAPI-based product. But it wasn’t just about sending messages — we had to handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scalable delivery&lt;/strong&gt; (thousands of users)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence&lt;/strong&gt; (so no message is lost)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unread tracking&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internationalization (i18n)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prioritization &amp;amp; retries&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The traditional Redis Pub/Sub model just didn’t cut it — messages would be lost if a user was offline. So we decided to &lt;strong&gt;re-architect using Redis Streams&lt;/strong&gt; for reliable and replayable messaging.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ The Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FastAPI&lt;/strong&gt;: Async Python framework for APIs and WebSockets
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis Streams&lt;/strong&gt;: Durable, ordered messaging system
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL&lt;/strong&gt;: To store notification history and unread status
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebSockets&lt;/strong&gt;: For pushing updates in real-time to the user
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pydantic &amp;amp; SQLAlchemy&lt;/strong&gt;: For models and data validation
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker + AWS Lambda (future)&lt;/strong&gt;: For production-ready deployment
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔄 How It Works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;A notification is created (user action, cron job, webhook, etc.)&lt;/li&gt;
&lt;li&gt;It's pushed into a &lt;strong&gt;Redis Stream&lt;/strong&gt; with metadata like &lt;code&gt;user_id&lt;/code&gt;, &lt;code&gt;priority&lt;/code&gt;, &lt;code&gt;lang&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Redis Stream consumer&lt;/strong&gt; reads it, stores it in PostgreSQL, and pushes to the WebSocket server.&lt;/li&gt;
&lt;li&gt;If the user is connected — great, they get it instantly!&lt;/li&gt;
&lt;li&gt;If not, it’s stored, marked as unread, and delivered when they come back online.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  ✨ Key Highlights
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Message durability&lt;/strong&gt; with Redis Streams
&lt;/li&gt;
&lt;li&gt;🔄 &lt;strong&gt;Replay logic&lt;/strong&gt; in consumer to handle restarts
&lt;/li&gt;
&lt;li&gt;🌍 &lt;strong&gt;Multi-language templates&lt;/strong&gt; per user
&lt;/li&gt;
&lt;li&gt;🔒 &lt;strong&gt;Secure WebSocket authentication&lt;/strong&gt; using JWT and &lt;code&gt;x-api-key&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;📬 &lt;strong&gt;Push fallback logic&lt;/strong&gt; coming soon (Slack/Email integration)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📈 What's Next?
&lt;/h2&gt;

&lt;p&gt;I’m looking to open-source this soon and write detailed breakdowns of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Redis Streams vs Pub/Sub for real-time systems&lt;/li&gt;
&lt;li&gt;Notification retry and backoff strategies&lt;/li&gt;
&lt;li&gt;WebSocket gateway with reconnect handling&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💬 Let’s Connect!
&lt;/h2&gt;

&lt;p&gt;Have you built similar real-time systems? Or explored Redis Streams for production workloads?&lt;/p&gt;

&lt;p&gt;Let’s connect, geek out, and share learnings!&lt;br&gt;&lt;br&gt;
Also, I’m open to feedback — especially since this is my first post 😄&lt;/p&gt;

</description>
      <category>fastapi</category>
      <category>redis</category>
      <category>systemdesign</category>
      <category>socket</category>
    </item>
  </channel>
</rss>
