<?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: opengrowthai_dev</title>
    <description>The latest articles on DEV Community by opengrowthai_dev (@opengrowthai_dev).</description>
    <link>https://dev.to/opengrowthai_dev</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4056209%2F43cd74ed-14f9-4b21-aea8-5de83fe36fcc.png</url>
      <title>DEV Community: opengrowthai_dev</title>
      <link>https://dev.to/opengrowthai_dev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/opengrowthai_dev"/>
    <language>en</language>
    <item>
      <title>Inside ORAG's Go API Startup Path: Configuration, Logging, and Failure Handling</title>
      <dc:creator>opengrowthai_dev</dc:creator>
      <pubDate>Fri, 31 Jul 2026 11:50:53 +0000</pubDate>
      <link>https://dev.to/opengrowthai_dev/inside-orags-go-api-startup-path-configuration-logging-and-failure-handling-5238</link>
      <guid>https://dev.to/opengrowthai_dev/inside-orags-go-api-startup-path-configuration-logging-and-failure-handling-5238</guid>
      <description>&lt;h2&gt;
  
  
  Intended Readers
&lt;/h2&gt;

&lt;p&gt;Go developers and system administrators who want to understand how ORAG initializes its API process before the HTTP server begins serving requests.&lt;/p&gt;

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

&lt;p&gt;An API server's startup path is easy to overlook until initialization fails. A useful entry point should make several questions answerable from the code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What happens when configuration cannot be loaded?&lt;/li&gt;
&lt;li&gt;Is logging available before the application is constructed?&lt;/li&gt;
&lt;li&gt;Can the HTTP server start after application initialization fails?&lt;/li&gt;
&lt;li&gt;How are shutdown errors surfaced?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ORAG keeps these decisions in a small &lt;code&gt;run&lt;/code&gt; function, separate from &lt;code&gt;main&lt;/code&gt;, so the initialization sequence and its failure behavior can be inspected directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Approach
&lt;/h2&gt;

&lt;p&gt;The process starts in &lt;code&gt;cmd/orag-api/main.go&lt;/code&gt;. Its &lt;code&gt;main&lt;/code&gt; function calls &lt;code&gt;run&lt;/code&gt; with three dependencies:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A background context.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;core.New&lt;/code&gt;, which builds the application.&lt;/li&gt;
&lt;li&gt;A server starter that creates the HTTP server and calls &lt;code&gt;Hertz().Spin()&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;run&lt;/code&gt; function then performs startup in a fixed order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Load configuration.&lt;/strong&gt; It calls &lt;code&gt;config.Load()&lt;/code&gt;. If loading fails, it writes a standard log message and returns exit code &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create the structured logger.&lt;/strong&gt; After configuration succeeds, it calls &lt;code&gt;logger.New(cfg.Server.Debug)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build the application.&lt;/strong&gt; The injected &lt;code&gt;buildApp&lt;/code&gt; function receives the context, configuration, and logger. An initialization error is logged as &lt;code&gt;init app failed&lt;/code&gt;, and &lt;code&gt;run&lt;/code&gt; returns &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Register cleanup.&lt;/strong&gt; Once the application exists, a deferred call closes it. A close failure is logged as &lt;code&gt;close app failed&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log startup context.&lt;/strong&gt; Before starting the server, ORAG logs &lt;code&gt;starting orag api&lt;/code&gt; with the configured address and &lt;code&gt;cfg.RedactedEnv()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start the server.&lt;/strong&gt; The injected starter receives the initialized application. If control returns normally, &lt;code&gt;run&lt;/code&gt; returns &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This dependency-injected shape also makes one important failure path testable. In &lt;code&gt;cmd/orag-api/main_test.go&lt;/code&gt;, the application builder deliberately returns an error. The test checks that &lt;code&gt;run&lt;/code&gt; returns &lt;code&gt;1&lt;/code&gt; and that the server starter is not called.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why This Structure Helps
&lt;/h3&gt;

&lt;p&gt;Keeping process wiring in &lt;code&gt;main&lt;/code&gt; and startup decisions in &lt;code&gt;run&lt;/code&gt; gives the initialization path a clear boundary. The application builder and server starter are passed in as functions, so the test can replace them without starting a real HTTP server. That is what allows the initialization-failure test to verify both the exit code and the fact that server startup was skipped.&lt;/p&gt;

&lt;p&gt;The same separation also keeps the startup sequence readable. Configuration loading, logger construction, application initialization, cleanup registration, and server startup remain visible in one function instead of being distributed across the process entry point. When one of these stages changes, its position in the startup lifecycle is easier to identify from the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage Steps: Reading and Trying the Startup Path
&lt;/h2&gt;

&lt;p&gt;These steps are a guide to the startup flow shown in the two evidence files. They do not guarantee that the API will run in a particular environment: successful startup still depends on configuration and dependencies outside the scope of this article, and the command below was not executed during evidence collection.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start with the entry point.&lt;/strong&gt; Open &lt;code&gt;cmd/orag-api/main.go&lt;/code&gt; and locate &lt;code&gt;main&lt;/code&gt;. It passes a context, &lt;code&gt;core.New&lt;/code&gt;, and the Hertz server starter into &lt;code&gt;run&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trace the guarded stages.&lt;/strong&gt; Read &lt;code&gt;run&lt;/code&gt; from top to bottom: configuration must load before the logger is created, and the application must build successfully before the server starter is called.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review the tested failure path.&lt;/strong&gt; Open &lt;code&gt;cmd/orag-api/main_test.go&lt;/code&gt; and inspect &lt;code&gt;TestRunReturnsNonZeroOnAppInitFailure&lt;/code&gt;. The injected builder returns an error, allowing the test to check the exit code without starting a server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prepare the wider project configuration before trying the command.&lt;/strong&gt; &lt;code&gt;config.Load()&lt;/code&gt; must succeed, but the complete configuration contract is outside the two evidence files used here. Consult the repository's configuration documentation rather than treating this article as a complete setup guide.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;From the repository root, use the documented entry file if you want to try the startup path:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   go run cmd/orag-api/main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Interpret any result in context.&lt;/strong&gt; A configuration error or missing dependency does not contradict the startup sequence described above. This article establishes the control flow from static evidence; it does not establish that a specific local environment is ready to run ORAG.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;buildApp&lt;/code&gt; fails, the application exits with a non-zero status code.&lt;/li&gt;
&lt;li&gt;The cited test covers application initialization failure; it does not establish runtime behavior for a successfully running HTTP server.&lt;/li&gt;
&lt;li&gt;The command and startup output described here were not executed as part of this article's evidence collection.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;ORAG's API entry point separates process wiring from startup logic. The resulting &lt;code&gt;run&lt;/code&gt; function makes the order explicit: load configuration, create logging, build the application, register cleanup, log redacted startup context, and only then start the HTTP server. Its test verifies that application initialization failure stops the sequence before server startup.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Question for Go Maintainers
&lt;/h2&gt;

&lt;p&gt;When you review a Go service entry point, which startup boundaries do you make directly testable? ORAG injects the application builder and server starter, then verifies that an initialization error prevents server startup. It would be interesting to compare this with approaches that move lifecycle wiring into a dedicated application type or use integration tests around the process boundary.&lt;/p&gt;

&lt;p&gt;If you want to inspect this particular design, the two evidence files below contain the complete startup path and its focused failure test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evidence and Verification
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Commit SHA: &lt;code&gt;534af21861be408fd4947ebae8e3e4db77e0a7e2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Feature: &lt;code&gt;API Server Initialization and Logging&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Evidence paths:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cmd/orag-api/main.go&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cmd/orag-api/main_test.go&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Not runtime verified: this article is based on static repository evidence.&lt;/li&gt;
&lt;/ul&gt;

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