<?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: Esa Data</title>
    <description>The latest articles on DEV Community by Esa Data (@esadata).</description>
    <link>https://dev.to/esadata</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%2F4135439%2F630d7e4d-0926-4c78-b8b8-a8d66f0b5c71.jpeg</url>
      <title>DEV Community: Esa Data</title>
      <link>https://dev.to/esadata</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/esadata"/>
    <language>en</language>
    <item>
      <title>From Telemetry to Automated Incident Response: My DevOps &amp; Observability Journey</title>
      <dc:creator>Esa Data</dc:creator>
      <pubDate>Sat, 03 Oct 2026 03:49:54 +0000</pubDate>
      <link>https://dev.to/esadata/from-telemetry-to-automated-incident-response-my-devops-observability-journey-2ob5</link>
      <guid>https://dev.to/esadata/from-telemetry-to-automated-incident-response-my-devops-observability-journey-2ob5</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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy2byhniwd79r1zlxj1x7.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy2byhniwd79r1zlxj1x7.png" alt="Observability and Incident Response Pipeline" width="800" height="840"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Description: A hands-on learning journey building observability and automated incident response into a FastAPI order-tracking application using OpenTelemetry, Prometheus, Loki, Tempo, Grafana, and Codex CLI.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  From Telemetry to Automated Incident Response
&lt;/h2&gt;

&lt;p&gt;As part of the &lt;strong&gt;DataTalksClub AI Dev Tools Zoomcamp&lt;/strong&gt;, I worked on a small but practical challenge: turning a simple FastAPI application into an observable system with automated incident response.&lt;/p&gt;

&lt;p&gt;The project started as a basic &lt;strong&gt;Order Tracker&lt;/strong&gt; application backed by SQLite.&lt;/p&gt;

&lt;p&gt;By the end, it had evolved into a system that could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;collect &lt;strong&gt;metrics, logs, and traces&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;visualize telemetry in &lt;strong&gt;Grafana&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;detect application errors through &lt;strong&gt;alerting&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;send incidents to an &lt;strong&gt;incident-response service&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;provide evidence for investigation&lt;/li&gt;
&lt;li&gt;trigger a coding agent to investigate and remediate an issue&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most valuable lesson for me was that observability is not just about collecting data.&lt;/p&gt;

&lt;p&gt;It is about connecting &lt;strong&gt;detection → investigation → remediation → verification&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;A basic application can work perfectly during development and still fail in production.&lt;/p&gt;

&lt;p&gt;For an order-tracking API, a failure might look simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/orders/express-1002
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;returns a server error.&lt;/p&gt;

&lt;p&gt;Without observability, the workflow often becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Something is broken
        ↓
Check application logs
        ↓
Search for the error
        ↓
Try to reproduce it
        ↓
Find the problematic code
        ↓
Apply a fix
        ↓
Restart the application
        ↓
Test again
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works, but it becomes increasingly difficult as the system grows.&lt;/p&gt;

&lt;p&gt;I wanted to build a workflow where telemetry could help connect these steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;The final architecture introduced several components:&lt;/p&gt;

&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy2byhniwd79r1zlxj1x7.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy2byhniwd79r1zlxj1x7.png" alt="Observability and Incident Response Pipeline" width="800" height="840"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This architecture separates telemetry collection, storage, visualization, alerting, and incident response.&lt;/p&gt;

&lt;h3&gt;
  
  
  Instrumenting the Application
&lt;/h3&gt;

&lt;p&gt;The first step was adding OpenTelemetry instrumentation to the FastAPI application.&lt;/p&gt;

&lt;p&gt;I wanted each order lookup to produce useful telemetry, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP route&lt;/li&gt;
&lt;li&gt;HTTP status code&lt;/li&gt;
&lt;li&gt;request information&lt;/li&gt;
&lt;li&gt;logs&lt;/li&gt;
&lt;li&gt;traces&lt;/li&gt;
&lt;li&gt;request metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/orders/standard-1001
→ 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/orders/standard-1002
→ 404
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part was not simply knowing that a request happened.&lt;/p&gt;

&lt;p&gt;The telemetry needed enough context to answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What endpoint failed, what was the HTTP status, and what happened during the request?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Adding the Observability Stack
&lt;/h3&gt;

&lt;p&gt;The next step was connecting the application to an observability stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OpenTelemetry Collector&lt;/strong&gt; — receives and routes telemetry&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prometheus&lt;/strong&gt; — metrics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loki&lt;/strong&gt; — logs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tempo&lt;/strong&gt; — traces&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grafana&lt;/strong&gt; — visualization and alerting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The OpenTelemetry Collector became the central telemetry pipeline.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application
    │
    │ OTLP
    ▼
OpenTelemetry Collector
    │
    ├── Metrics → Prometheus
    │
    ├── Logs    → Loki
    │
    └── Traces  → Tempo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Grafana then provides a single interface for exploring these signals.&lt;/p&gt;

&lt;p&gt;This was one of the important lessons from the project:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Metrics tell you that something is happening.&lt;br&gt;
Logs help explain what happened.&lt;br&gt;
Traces help show where it happened.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Using the three together provides much more useful operational context than relying on a single signal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grafana Alerting
&lt;/h3&gt;

&lt;p&gt;After telemetry was available, I configured Grafana alerting for server-side failures.&lt;/p&gt;

&lt;p&gt;The goal was to detect &lt;strong&gt;5xx responses&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A 404 response such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/orders/standard-1002
→ 404
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;should not trigger the 5xx incident workflow.&lt;/p&gt;

&lt;p&gt;This distinction was useful because it forced me to think about alert conditions rather than simply alerting on every failed request.&lt;/p&gt;

&lt;p&gt;The alert also needed to provide enough information for the next stage of the workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automated Incident Response
&lt;/h3&gt;

&lt;p&gt;The next step was adding a dedicated incident-response service.&lt;/p&gt;

&lt;p&gt;The service exposes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /alerts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When Grafana sends an alert, the responder stores the incident information and gathers useful evidence.&lt;/p&gt;

&lt;p&gt;The idea is to transform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Grafana Alert
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Incident
├── endpoint
├── status
├── logs
├── traces
└── investigation context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a bridge between observability and automated remediation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting an AI Coding Agent
&lt;/h3&gt;

&lt;p&gt;The most interesting part of the exercise was connecting the incident workflow to a coding agent.&lt;/p&gt;

&lt;p&gt;Instead of simply notifying a developer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🚨 500 error detected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the system can provide the coding agent with context about the incident.&lt;/p&gt;

&lt;p&gt;The intended workflow becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;5xx detected
     ↓
Grafana alert
     ↓
Incident-response service
     ↓
Collect evidence
     ↓
Coding agent investigates
     ↓
Identify root cause
     ↓
Apply fix
     ↓
Restart application
     ↓
Verify behavior
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This changes the role of AI from simply generating code to participating in an operational workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Finding the Bug
&lt;/h3&gt;

&lt;p&gt;The final exercise intentionally exposed a bug in the Express order lookup.&lt;/p&gt;

&lt;p&gt;The problematic implementation calculated the estimated delivery date using:&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;estimated_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;placed_at&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;placed_at&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks reasonable at first glance.&lt;/p&gt;

&lt;p&gt;However, it assumes that the resulting day exists in the same month.&lt;/p&gt;

&lt;p&gt;For an order created near the end of a month, that assumption can fail.&lt;/p&gt;

&lt;p&gt;The fix was to use date arithmetic instead:&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;estimated_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;placed_at&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows Python's datetime implementation to correctly handle month boundaries.&lt;/p&gt;

&lt;p&gt;The important part was not only finding the line of code.&lt;/p&gt;

&lt;p&gt;The observability and incident-response workflow provided the path from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP failure
    ↓
Telemetry
    ↓
Alert
    ↓
Incident evidence
    ↓
Root-cause investigation
    ↓
Code change
    ↓
Verification
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What I Learned
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Observability is more than logging
&lt;/h4&gt;

&lt;p&gt;Before this project, it was easy to think of observability as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Add some logs."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The project changed that perspective.&lt;/p&gt;

&lt;p&gt;A useful observability system combines multiple signals and makes them actionable.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Alerts need context
&lt;/h4&gt;

&lt;p&gt;An alert saying:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Something went wrong
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is not particularly useful.&lt;/p&gt;

&lt;p&gt;An actionable incident should provide enough context to start an investigation.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Endpoint
HTTP status
Logs
Trace
Time window
Dashboard context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Automation should be connected to verification
&lt;/h4&gt;

&lt;p&gt;Automatically changing code is not enough.&lt;/p&gt;

&lt;p&gt;A remediation workflow should also verify that the application works after the change.&lt;/p&gt;

&lt;p&gt;That makes the workflow closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Detect → Investigate → Fix → Verify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;rather than simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Detect → Fix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. AI agents need operational context
&lt;/h4&gt;

&lt;p&gt;A coding agent becomes much more useful when it receives evidence from the system instead of being asked to investigate blindly.&lt;/p&gt;

&lt;p&gt;Telemetry can provide the context needed for the agent to understand what actually happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  Technology Stack
&lt;/h3&gt;

&lt;p&gt;The project brought several tools together:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;API&lt;/td&gt;
&lt;td&gt;FastAPI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;SQLite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Telemetry&lt;/td&gt;
&lt;td&gt;OpenTelemetry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Telemetry Pipeline&lt;/td&gt;
&lt;td&gt;OpenTelemetry Collector&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Metrics&lt;/td&gt;
&lt;td&gt;Prometheus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logs&lt;/td&gt;
&lt;td&gt;Loki&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Traces&lt;/td&gt;
&lt;td&gt;Tempo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Visualization&lt;/td&gt;
&lt;td&gt;Grafana&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Containers&lt;/td&gt;
&lt;td&gt;Docker / Docker Compose&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI-assisted remediation&lt;/td&gt;
&lt;td&gt;Codex CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Verification
&lt;/h3&gt;

&lt;p&gt;The completed workflow was validated through the homework tasks.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Q1&lt;/td&gt;
&lt;td&gt;Application health check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;200&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q2&lt;/td&gt;
&lt;td&gt;Existing order lookup&lt;/td&gt;
&lt;td&gt;&lt;code&gt;200&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q3&lt;/td&gt;
&lt;td&gt;Missing order lookup&lt;/td&gt;
&lt;td&gt;&lt;code&gt;404&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q4&lt;/td&gt;
&lt;td&gt;5xx alert behavior&lt;/td&gt;
&lt;td&gt;Normal for 404&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q5&lt;/td&gt;
&lt;td&gt;Incident-response workflow&lt;/td&gt;
&lt;td&gt;Completed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q6&lt;/td&gt;
&lt;td&gt;Express order incident&lt;/td&gt;
&lt;td&gt;Root cause identified and fixed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The important outcome was not just that each individual component worked.&lt;/p&gt;

&lt;p&gt;The complete workflow worked as a chain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Takeaway
&lt;/h3&gt;

&lt;p&gt;The biggest lesson from this project was that &lt;strong&gt;observability becomes much more valuable when it is connected to action&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A mature workflow can look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application
     ↓
Telemetry
     ↓
Observability
     ↓
Alerting
     ↓
Incident Response
     ↓
AI-assisted Investigation
     ↓
Remediation
     ↓
Verification
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This project gave me hands-on experience connecting these pieces together rather than learning them as isolated technologies.&lt;/p&gt;

&lt;p&gt;For me, that's the real value of &lt;strong&gt;Learning in Public&lt;/strong&gt;: documenting not only what I built, but also the problems I encountered, the root causes I found, and what changed in my understanding along the way.&lt;/p&gt;




&lt;h3&gt;
  
  
  Acknowledgments
&lt;/h3&gt;

&lt;p&gt;This project was completed as part of the &lt;strong&gt;DataTalksClub AI Dev Tools Zoomcamp — Homework 4: DevOps and Observability for AI-Built Apps&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Thanks to the DataTalksClub community for creating practical exercises that connect software development, DevOps, observability, and AI-assisted engineering.&lt;/p&gt;




&lt;p&gt;Github Repository: &lt;a href="https://github.com/ketut-garjita/order-tracker-v2" rel="noopener noreferrer"&gt;order-tracker-v2&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>observability</category>
      <category>opentelemetry</category>
      <category>ai</category>
    </item>
    <item>
      <title>Agent Relay v2</title>
      <dc:creator>Esa Data</dc:creator>
      <pubDate>Mon, 21 Sep 2026 10:44:14 +0000</pubDate>
      <link>https://dev.to/esadata/agent-relay-v2-28aa</link>
      <guid>https://dev.to/esadata/agent-relay-v2-28aa</guid>
      <description>&lt;h2&gt;
  
  
  From SQLite to Kubernetes: Building a Test-Gated CI/CD Pipeline for a Task Relay Service
&lt;/h2&gt;

&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyn7apvrukhlapq4d7emn.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyn7apvrukhlapq4d7emn.png" alt="Agent-Relay v2 Architecture" width="652" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I recently completed an engineering exercise that started as a small FastAPI + SQLite application and gradually evolved into a containerized, Kubernetes-deployed service with a full CI/CD pipeline.&lt;br&gt;
The project is Agent Relay — a task relay service for registering agents, delivering tasks, tracking claims, and recording results.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The evolution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SQLite → PostgreSQL → Docker → Kubernetes (Kind) → GitHub Actions CI/CD&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What made this interesting wasn't just "getting it running" — it was watching each layer expose a new class of problem that the previous layer didn't have to deal with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I implemented and verified along the way&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;• Agent registration and authentication&lt;br&gt;
• At-least-once task delivery&lt;br&gt;
• Lease-based task claims&lt;br&gt;
• Worker heartbeats&lt;br&gt;
• Task recovery after worker failure&lt;br&gt;
• Idempotent terminal requests&lt;br&gt;
• PostgreSQL persistence&lt;br&gt;
• Docker containerization&lt;br&gt;
• Kubernetes Deployment, Service, Secret, and PVC&lt;br&gt;
• Automated pytest verification&lt;br&gt;
• Git SHA-based Docker image tagging&lt;br&gt;
• Test-gated CI/CD&lt;br&gt;
• End-to-end deployment verification&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The lesson that mattered most&lt;/strong&gt;&lt;br&gt;
A successful Kubernetes rollout does not mean an application is actually working. kubectl rollout status can go green while the app underneath is silently broken — a bad config, a missing secret, a dependency that never connected.&lt;br&gt;
So the pipeline doesn't stop at "the pods are Running." After deployment, it port-forwards the service and runs an application-level check against the dashboard — the same kind of check a human would do by opening the page and looking at it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The pipeline, accurately&lt;/strong&gt;&lt;br&gt;
My first pass at diagramming this pipeline drew pytest, Docker build, and Kubernetes deployment as three parallel branches. That's not what actually happens. The real pipeline is sequential and test-gated: nothing gets built or deployed unless the tests pass first.&lt;/p&gt;

&lt;p&gt;Developer&lt;br&gt;
   ↓&lt;br&gt;
Git Repository (push)&lt;br&gt;
   ↓&lt;br&gt;
GitHub Actions&lt;br&gt;
   ↓&lt;br&gt;
job: test&lt;br&gt;
   ├── setup Python 3.11 + uv&lt;br&gt;
   ├── Postgres 16-alpine (service container)&lt;br&gt;
   └── uv run pytest -q&lt;br&gt;
   ↓  (needs: test → only proceeds if tests pass)&lt;br&gt;
job: build-and-deploy&lt;br&gt;
   ├── Docker build (image tagged with Git SHA)&lt;br&gt;
   └── deploy to Kind cluster&lt;br&gt;
          ├── kubectl apply -f k8s/&lt;br&gt;
          ├── kubectl set image&lt;br&gt;
          └── rollout status&lt;br&gt;
                ↓&lt;br&gt;
        Agent Relay (FastAPI service, incl. dashboard)&lt;br&gt;
                ↓&lt;br&gt;
        Verification: port-forward + curl → dashboard check&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this matters beyond one project&lt;/strong&gt;&lt;br&gt;
The instinct to treat "deployed" as "done" is exactly the instinct that breaks pipelines at scale. Whether it's a Kubernetes rollout or a data/ML pipeline, the pattern is the same: infrastructure-level success (pod is Running, DAG task is green) is not application-level success (the thing actually does what it's supposed to do). Closing that gap with a real, purpose-built check — not just a health probe — is what turns "it deployed" into "it works."&lt;/p&gt;

&lt;p&gt;I'm currently exploring how these same engineering principles — test gating, staged evolution, verifying at the application level rather than the infrastructure level — apply to larger Data Engineering and AI/LLM systems, where the failure modes are often even less visible than a crashed pod.&lt;/p&gt;

&lt;p&gt;The repository contains the implementation, Kubernetes manifests, Docker configuration, automated tests, and the CI/CD workflow.&lt;/p&gt;

&lt;p&gt;GitHub repo: &lt;a href="https://github.com/ketut-garjita/agent-relay" rel="noopener noreferrer"&gt;https://github.com/ketut-garjita/agent-relay&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>cicd</category>
      <category>devops</category>
      <category>kubernetes</category>
    </item>
  </channel>
</rss>
