<?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: Mohammad Abdolirad</title>
    <description>The latest articles on Forem by Mohammad Abdolirad (@atkrad).</description>
    <link>https://forem.com/atkrad</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%2F548946%2Fcddb4340-65c7-4f75-9a6e-8a589630412a.jpeg</url>
      <title>Forem: Mohammad Abdolirad</title>
      <link>https://forem.com/atkrad</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/atkrad"/>
    <language>en</language>
    <item>
      <title>Why I Built Rivaas: A Go Framework That Grows With You</title>
      <dc:creator>Mohammad Abdolirad</dc:creator>
      <pubDate>Mon, 26 Jan 2026 11:51:17 +0000</pubDate>
      <link>https://forem.com/atkrad/why-i-built-rivaas-a-go-framework-that-grows-with-you-26pg</link>
      <guid>https://forem.com/atkrad/why-i-built-rivaas-a-go-framework-that-grows-with-you-26pg</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzngqk0jjb9srqu7mj25.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzngqk0jjb9srqu7mj25.png" alt="Rivaas Logo" width="256" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I used Gin for years. Then my API grew, and things got messy.&lt;/p&gt;

&lt;p&gt;Let me tell you why I built Rivaas. This isn't about saying other frameworks are bad. They're great. But I needed something different.&lt;/p&gt;

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

&lt;p&gt;Three years ago, I started a simple API. Just a few endpoints. I picked Gin because it was fast and popular.&lt;/p&gt;

&lt;p&gt;The API worked well. Then the project grew.&lt;/p&gt;

&lt;h3&gt;
  
  
  Observability Was Bolted On
&lt;/h3&gt;

&lt;p&gt;We needed to track metrics. I added Prometheus manually. Connected it to the routes. Added custom middleware.&lt;/p&gt;

&lt;p&gt;Then we needed tracing. I added Jaeger. More middleware. More manual work.&lt;/p&gt;

&lt;p&gt;Then we needed structured logging. Another library. More integration code.&lt;/p&gt;

&lt;p&gt;Each piece worked. But nothing talked to each other. Logs didn't include trace IDs. Metrics didn't match route names. Every new feature meant writing more glue code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration Was Scattered
&lt;/h3&gt;

&lt;p&gt;Environment variables were everywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PORT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;dbHost&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DB_HOST"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;logLevel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"LOG_LEVEL"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// ... 30 more lines ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some config came from files. Some from env vars. Some was hardcoded. When you needed to change something, you had to search through multiple files.&lt;/p&gt;

&lt;h3&gt;
  
  
  No Lifecycle Management
&lt;/h3&gt;

&lt;p&gt;When we shut down the server, we had to remember to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stop accepting new requests&lt;/li&gt;
&lt;li&gt;Wait for current requests to finish&lt;/li&gt;
&lt;li&gt;Close database connections&lt;/li&gt;
&lt;li&gt;Flush metrics&lt;/li&gt;
&lt;li&gt;Close tracing exporters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was all manual. Miss one step and you lose data or get errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validation Was Manual
&lt;/h3&gt;

&lt;p&gt;Every endpoint needed validation code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"email required"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isValidEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invalid email"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;18&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"must be 18 or older"&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;Multiply this by 50 endpoints. That's a lot of boring code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Name: Wild Rhubarb
&lt;/h2&gt;

&lt;p&gt;I needed a name for this project. I wanted something meaningful.&lt;/p&gt;

&lt;p&gt;I thought about what I wanted the framework to be. Then I remembered &lt;strong&gt;ریواس (Rivās)&lt;/strong&gt; - wild rhubarb.&lt;/p&gt;

&lt;p&gt;This plant grows in the mountains of Iran. At 1,500 to 3,000 meters altitude. The weather is harsh. The soil is poor. Few plants can survive there.&lt;/p&gt;

&lt;p&gt;But Rivās thrives. It has four special qualities:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Resilient
&lt;/h3&gt;

&lt;p&gt;Rivās survives freezing winters and hot summers. It handles extreme conditions.&lt;/p&gt;

&lt;p&gt;Your API needs to be resilient too. It should handle panics gracefully. Shut down properly. Recover from errors.&lt;/p&gt;

&lt;p&gt;Rivaas includes panic recovery, graceful shutdown, and health checks. Your service stays up even when things go wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Lightweight
&lt;/h3&gt;

&lt;p&gt;Rivās doesn't need much. Poor soil is fine. Little water is enough.&lt;/p&gt;

&lt;p&gt;Your framework should be the same. It shouldn't use tons of memory. It shouldn't slow down your app.&lt;/p&gt;

&lt;p&gt;Rivaas uses 16 bytes per request. It handles 8.4 million requests per second. You don't need huge servers to run it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Adaptive
&lt;/h3&gt;

&lt;p&gt;Rivās grows at different altitudes. In valleys and on peaks. It adapts to its environment.&lt;/p&gt;

&lt;p&gt;Your API runs in different places too. Your laptop. A container. A Kubernetes cluster.&lt;/p&gt;

&lt;p&gt;Rivaas works everywhere. Same code, different environments. It detects what's available and adapts.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Self-Sufficient
&lt;/h3&gt;

&lt;p&gt;Rivās doesn't depend on other plants. It grows on its own.&lt;/p&gt;

&lt;p&gt;Your framework should include what you need. Not force you to find and connect dozens of libraries.&lt;/p&gt;

&lt;p&gt;Rivaas includes metrics, tracing, logging, validation, and config management. Everything talks to each other. You don't write glue code.&lt;/p&gt;

&lt;p&gt;These four qualities guide every decision in Rivaas.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Wanted
&lt;/h2&gt;

&lt;p&gt;I sat down and made a list. What would my ideal framework look like?&lt;/p&gt;

&lt;h3&gt;
  
  
  Batteries Included, But Not Locked In
&lt;/h3&gt;

&lt;p&gt;Most frameworks are either bare minimum or all-in.&lt;/p&gt;

&lt;p&gt;Bare minimum frameworks give you routing. You add everything else yourself.&lt;/p&gt;

&lt;p&gt;All-in frameworks give you everything. But you can't swap parts out.&lt;/p&gt;

&lt;p&gt;I wanted both. Give me good defaults. But let me replace anything.&lt;/p&gt;

&lt;p&gt;Rivaas works like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Use the full framework&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithObservability&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithMetrics&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTracing&lt;/span&gt;&lt;span class="p"&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;Or use just the parts you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Use just the router&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;// Add your own metrics library&lt;/span&gt;
&lt;span class="c"&gt;// Add your own tracing&lt;/span&gt;
&lt;span class="c"&gt;// Full control&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each package has its own &lt;code&gt;go.mod&lt;/code&gt;. You can use one without the others.&lt;/p&gt;

&lt;h3&gt;
  
  
  Observability Built In, Not Added Later
&lt;/h3&gt;

&lt;p&gt;Metrics, tracing, and logging should be first-class features. Not afterthoughts.&lt;/p&gt;

&lt;p&gt;In Rivaas, observability is integrated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logs include trace IDs automatically&lt;/li&gt;
&lt;li&gt;Metrics use the same service name as traces&lt;/li&gt;
&lt;li&gt;Everything is configured in one place&lt;/li&gt;
&lt;li&gt;It all works together&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You turn it on with one option. You don't write integration code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Production-Ready Defaults
&lt;/h3&gt;

&lt;p&gt;Most frameworks give you dev-friendly defaults. Then you search for "production configuration" and copy code from Stack Overflow.&lt;/p&gt;

&lt;p&gt;Rivaas has production-ready defaults:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Graceful shutdown with timeout&lt;/li&gt;
&lt;li&gt;Health endpoints for Kubernetes&lt;/li&gt;
&lt;li&gt;Panic recovery middleware&lt;/li&gt;
&lt;li&gt;Structured JSON logging&lt;/li&gt;
&lt;li&gt;Request timeouts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can override anything. But the defaults work in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clear Error Messages
&lt;/h3&gt;

&lt;p&gt;When something goes wrong, the error should tell you exactly what happened.&lt;/p&gt;

&lt;p&gt;Bad error: &lt;code&gt;validation failed&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Good error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Validation Failed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"detail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The request body contains invalid data"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"errors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"must be a valid email address"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"not-an-email"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"must be at least 18"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rivaas gives you the second type. Your frontend developers will thank you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design Decisions
&lt;/h2&gt;

&lt;p&gt;I made some choices early on. These shaped how Rivaas works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modular Architecture
&lt;/h3&gt;

&lt;p&gt;Each package is independent. Each has its own &lt;code&gt;go.mod&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rivaas/
├── app/          → rivaas.dev/app
├── router/       → rivaas.dev/router
├── binding/      → rivaas.dev/binding
├── validation/   → rivaas.dev/validation
├── config/       → rivaas.dev/config
├── logging/      → rivaas.dev/logging
├── metrics/      → rivaas.dev/metrics
├── tracing/      → rivaas.dev/tracing
└── ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You install what you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Full framework&lt;/span&gt;
go get rivaas.dev/app

&lt;span class="c"&gt;# Just the router&lt;/span&gt;
go get rivaas.dev/router

&lt;span class="c"&gt;# Just config management&lt;/span&gt;
go get rivaas.dev/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Functional Options Pattern
&lt;/h3&gt;

&lt;p&gt;Every package uses the same configuration pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithPort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&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;This makes the API consistent. Once you learn it in one package, you know it everywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  The App Package as Integration Layer
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;app&lt;/code&gt; package doesn't have much code. It's mostly integration.&lt;/p&gt;

&lt;p&gt;It takes all the other packages and connects them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sets the service name everywhere&lt;/li&gt;
&lt;li&gt;Connects logs to traces&lt;/li&gt;
&lt;li&gt;Sets up health checks&lt;/li&gt;
&lt;li&gt;Manages lifecycle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can use &lt;code&gt;app&lt;/code&gt; for convenience. Or skip it and wire things yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes It Different
&lt;/h2&gt;

&lt;p&gt;There are many Go frameworks. Why choose Rivaas?&lt;/p&gt;

&lt;p&gt;Here's an honest comparison:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Rivaas&lt;/th&gt;
&lt;th&gt;Gin&lt;/th&gt;
&lt;th&gt;Echo&lt;/th&gt;
&lt;th&gt;Chi&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Router speed&lt;/td&gt;
&lt;td&gt;⚡⚡⚡&lt;/td&gt;
&lt;td&gt;⚡⚡⚡&lt;/td&gt;
&lt;td&gt;⚡⚡⚡&lt;/td&gt;
&lt;td&gt;⚡⚡&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built-in observability&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automatic OpenAPI&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Graceful shutdown&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Health endpoints&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modular packages&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validation strategies&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Config management&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(✅ = built-in, ⚠️ = basic, ❌ = not included)&lt;/p&gt;

&lt;p&gt;Rivaas isn't always better. But it includes more out of the box.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to Use Rivaas
&lt;/h3&gt;

&lt;p&gt;Choose Rivaas if you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Want observability without setup&lt;/li&gt;
&lt;li&gt;Need automatic API documentation&lt;/li&gt;
&lt;li&gt;Build cloud-native services&lt;/li&gt;
&lt;li&gt;Want production-ready defaults&lt;/li&gt;
&lt;li&gt;Like modular design&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When Not to Use Rivaas
&lt;/h3&gt;

&lt;p&gt;Don't choose Rivaas if you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Need the absolute smallest binary&lt;/li&gt;
&lt;li&gt;Want to control every detail&lt;/li&gt;
&lt;li&gt;Already have a working setup with another framework&lt;/li&gt;
&lt;li&gt;Prefer older, more stable frameworks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Be honest with yourself about your needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Journey
&lt;/h2&gt;

&lt;p&gt;Building Rivaas took time. Here's what I learned.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start Small
&lt;/h3&gt;

&lt;p&gt;I didn't build everything at once. I started with the router. Made it fast. Then added binding. Then validation.&lt;/p&gt;

&lt;p&gt;Each piece got attention. Nothing was rushed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Listen to Users
&lt;/h3&gt;

&lt;p&gt;Early users had good ideas. They found bugs. They asked for features I hadn't thought about.&lt;/p&gt;

&lt;p&gt;The OpenAPI generation came from user requests. So did the multiple validation strategies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make Hard Choices
&lt;/h3&gt;

&lt;p&gt;I wanted to support everything. But that's impossible.&lt;/p&gt;

&lt;p&gt;We dropped some features. We said no to some requests. This kept the codebase clean.&lt;/p&gt;

&lt;p&gt;Every feature has a maintenance cost. We only add features that are worth it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Document Everything
&lt;/h3&gt;

&lt;p&gt;Code without docs is useless. I wrote guides for every package. Examples for every feature.&lt;/p&gt;

&lt;p&gt;Good documentation takes longer than code. But it's worth it.&lt;/p&gt;

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

&lt;p&gt;Rivaas is ready for production. But there's more to do.&lt;/p&gt;

&lt;h3&gt;
  
  
  Community Growth
&lt;/h3&gt;

&lt;p&gt;We need more contributors. More examples. More tutorials.&lt;/p&gt;

&lt;p&gt;If you use Rivaas, share your experience. Write about it. Help others.&lt;/p&gt;

&lt;h3&gt;
  
  
  More Integrations
&lt;/h3&gt;

&lt;p&gt;We want to integrate with more tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More database helpers&lt;/li&gt;
&lt;li&gt;More auth strategies&lt;/li&gt;
&lt;li&gt;More deployment examples&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Performance Improvements
&lt;/h3&gt;

&lt;p&gt;8.4 million requests per second is good. But we can do better.&lt;/p&gt;

&lt;p&gt;We're always looking for optimizations. Small gains add up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stability and Polish
&lt;/h3&gt;

&lt;p&gt;Every release makes Rivaas more stable. We fix bugs fast. We improve APIs based on feedback.&lt;/p&gt;

&lt;p&gt;The goal is a framework you can trust in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Contribute
&lt;/h2&gt;

&lt;p&gt;Want to help? Here's how:&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Rivaas
&lt;/h3&gt;

&lt;p&gt;The best way to help is to use it. Build something. Find bugs. Share feedback.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write About It
&lt;/h3&gt;

&lt;p&gt;Write a blog post. Make a video. Share on social media.&lt;/p&gt;

&lt;p&gt;Help others discover Rivaas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Contribute Code
&lt;/h3&gt;

&lt;p&gt;Check the &lt;a href="https://github.com/rivaas-dev/rivaas/issues" rel="noopener noreferrer"&gt;issues&lt;/a&gt; on GitHub. Look for "good first issue" tags.&lt;/p&gt;

&lt;p&gt;Write tests. Fix bugs. Add features.&lt;/p&gt;

&lt;h3&gt;
  
  
  Improve Documentation
&lt;/h3&gt;

&lt;p&gt;Found a confusing doc? Fix it. Missing an example? Add it.&lt;/p&gt;

&lt;p&gt;Documentation improvements are always welcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I built Rivaas because I needed it. Maybe you need it too.&lt;/p&gt;

&lt;p&gt;It's not perfect. No framework is. But it solves real problems.&lt;/p&gt;

&lt;p&gt;It gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speed without complexity&lt;/li&gt;
&lt;li&gt;Features without bloat&lt;/li&gt;
&lt;li&gt;Flexibility without chaos&lt;/li&gt;
&lt;li&gt;Production-ready without configuration hell&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try it in your next project. See if it fits your needs.&lt;/p&gt;

&lt;p&gt;If it does, great. If not, that's fine too. Choose what works for you.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Get Started&lt;/strong&gt;: &lt;code&gt;go get rivaas.dev/app&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Read the Docs&lt;/strong&gt;: &lt;a href="https://rivaas.dev/docs/" rel="noopener noreferrer"&gt;rivaas.dev/docs&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;View the Code&lt;/strong&gt;: &lt;a href="https://github.com/rivaas-dev/rivaas" rel="noopener noreferrer"&gt;github.com/rivaas-dev/rivaas&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Join Discussions&lt;/strong&gt;: &lt;a href="https://github.com/rivaas-dev/rivaas/discussions" rel="noopener noreferrer"&gt;GitHub Discussions&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>rivaas</category>
      <category>tutorial</category>
      <category>framework</category>
    </item>
    <item>
      <title>Ensuring Service Availability in Modern Infrastructure with Wait4X's TCP Checker</title>
      <dc:creator>Mohammad Abdolirad</dc:creator>
      <pubDate>Mon, 24 Mar 2025 16:10:13 +0000</pubDate>
      <link>https://forem.com/atkrad/ensuring-service-availability-in-modern-infrastructure-with-wait4xs-tcp-checker-3jg2</link>
      <guid>https://forem.com/atkrad/ensuring-service-availability-in-modern-infrastructure-with-wait4xs-tcp-checker-3jg2</guid>
      <description>&lt;p&gt;Are you tired of race conditions in your deployment pipelines? Ever run into those pesky "connection refused" errors when your application starts before its dependencies? Today I'll introduce you to Wait4X's TCP checker - a powerful tool for ensuring your services are ready before your application tries to connect.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Wait4X?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/wait4x/wait4x" rel="noopener noreferrer"&gt;Wait4X&lt;/a&gt; is a lightweight, zero-dependency tool designed to wait for services to be ready before continuing. It's a Swiss Army knife for service readiness checks, supporting multiple protocols and integrations including TCP, HTTP, DNS, and various databases.&lt;/p&gt;

&lt;h2&gt;
  
  
  The TCP Checker: Simple Yet Powerful
&lt;/h2&gt;

&lt;p&gt;At its core, the TCP checker does one thing extremely well: it attempts to establish a TCP connection to a specified address and port. If the connection succeeds, the service is considered ready; if it fails, Wait4X will retry based on your configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Usage
&lt;/h2&gt;

&lt;p&gt;The simplest way to use Wait4X's TCP checker is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wait4x tcp localhost:3306
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will attempt to connect to MySQL running on the default port, retrying until it succeeds or times out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Options
&lt;/h2&gt;

&lt;p&gt;Wait4X offers several options to fine-tune TCP checking behavior:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Connection timeout: Specify how long to wait for each connection attempt&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wait4x tcp localhost:8080 &lt;span class="nt"&gt;--connection-timeout&lt;/span&gt; 5s
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Retry interval: Control how frequently to retry&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wait4x tcp localhost:8080 &lt;span class="nt"&gt;--interval&lt;/span&gt; 2s
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Exponential backoff: Use smarter retry strategies&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wait4x tcp localhost:8080 &lt;span class="nt"&gt;--backoff-policy&lt;/span&gt; exponential &lt;span class="nt"&gt;--backoff-exponential-coefficient&lt;/span&gt; 2.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Multiple endpoints: Check multiple services in parallel&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wait4x tcp localhost:3306 localhost:6379 localhost:27017
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reverse checking: Wait for a port to become free&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wait4x tcp localhost:8080 &lt;span class="nt"&gt;--invert-check&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Real-world Use Cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Docker Compose Orchestration
&lt;/h3&gt;

&lt;p&gt;When working with Docker Compose, you often have dependencies between services. Using Wait4X, you can ensure services start in the right order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:13&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5432:5432"&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;

  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./api&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sh -c "wait4x tcp db:5432 &amp;amp;&amp;amp; npm start"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CI/CD Pipelines
&lt;/h3&gt;

&lt;p&gt;In CI/CD pipelines, Wait4X ensures tests don't run until services are ready:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start services&lt;/span&gt;
docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;

&lt;span class="c"&gt;# Wait for services to be ready&lt;/span&gt;
wait4x tcp localhost:3306 localhost:6379

&lt;span class="c"&gt;# Run tests&lt;/span&gt;
npm &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Kubernetes Init Containers
&lt;/h3&gt;

&lt;p&gt;Wait4X is perfect for Kubernetes init containers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;initContainers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;wait-for-db&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;wait4x/wait4x:latest&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wait4x"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tcp"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;postgres-service:5432"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--timeout"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;60s"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app:latest&lt;/span&gt;
          &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using Wait4X as a Go Package
&lt;/h3&gt;

&lt;p&gt;For Go developers, Wait4X provides a clean API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Create a context with timeout&lt;/span&gt;
&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;// Create a TCP checker&lt;/span&gt;
&lt;span class="n"&gt;tcpChecker&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;tcp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"localhost:6379"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tcp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c"&gt;// Wait for the TCP port to be available&lt;/span&gt;
&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;waiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tcpChecker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;waiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Minute&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;waiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;waiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithBackoffPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"exponential"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to connect: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Service is ready!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  How it Works Under the Hood
&lt;/h4&gt;

&lt;p&gt;Wait4X's TCP checker uses Go's net.Dialer.DialContext to attempt TCP connections with configurable timeouts. It handles various error cases intelligently, distinguishing between connection refusals, timeouts, and other network issues.&lt;/p&gt;

&lt;p&gt;The exponential backoff strategy progressively increases the interval between retries, reducing unnecessary connection attempts while still responding quickly when services become available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Wait4X's TCP checker solves a common but critical challenge in modern infrastructure: ensuring services are actually ready before dependent applications attempt to connect. By providing a simple, reliable way to check TCP connectivity, Wait4X helps eliminate race conditions, reduce errors, and make your deployments more robust.&lt;/p&gt;

&lt;p&gt;Give Wait4X a try in your next project - your deployment pipelines will thank you!&lt;/p&gt;




&lt;p&gt;What service readiness problems have you encountered in your infrastructure? Share your experiences in the comments!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>kubernetes</category>
      <category>go</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
