<?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: James Lee</title>
    <description>The latest articles on Forem by James Lee (@jamesli).</description>
    <link>https://forem.com/jamesli</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%2F2415836%2Fb3164384-9e59-4018-8224-c72be9619c2e.jpg</url>
      <title>Forem: James Lee</title>
      <link>https://forem.com/jamesli</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jamesli"/>
    <language>en</language>
    <item>
      <title>Full Observability in Istio: Metrics with Prometheus/Grafana + Distributed Tracing with Jaeger</title>
      <dc:creator>James Lee</dc:creator>
      <pubDate>Fri, 22 May 2026 10:16:22 +0000</pubDate>
      <link>https://forem.com/jamesli/full-observability-in-istio-metrics-with-prometheusgrafana-distributed-tracing-with-jaeger-3b8g</link>
      <guid>https://forem.com/jamesli/full-observability-in-istio-metrics-with-prometheusgrafana-distributed-tracing-with-jaeger-3b8g</guid>
      <description>&lt;p&gt;Observability is the ability to understand the internal state of a system from its external outputs. In a microservices architecture — where a single API call may fan out to dozens of services and hundreds of DB queries — observability is not optional. It's survival.&lt;/p&gt;

&lt;p&gt;Istio provides three pillars of observability out of the box:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pillar&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Metrics&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Prometheus + Grafana&lt;/td&gt;
&lt;td&gt;Trend analysis, QPS, latency, error rate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Distributed Tracing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Jaeger&lt;/td&gt;
&lt;td&gt;Root cause analysis of slow/failed requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Logging&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ELK Stack&lt;/td&gt;
&lt;td&gt;Detailed per-request log investigation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This article covers the first two in depth.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: Metrics with Prometheus + Grafana
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Prometheus Over StatsD or InfluxDB?
&lt;/h3&gt;

&lt;p&gt;Three metrics systems are commonly used in modern infrastructure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;StatsD + Graphite    →  UDP push model, lightweight, limited ecosystem
InfluxDB + Telegraf  →  Rich system-level plugins, custom app metrics need manual work
Prometheus           →  Pull model, native K8s/Consul service discovery, full alerting stack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prometheus wins in cloud-native environments for two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pull model&lt;/strong&gt; — Prometheus scrapes targets over HTTP. This simplifies client code and makes debugging trivial (just &lt;code&gt;curl&lt;/code&gt; the &lt;code&gt;/metrics&lt;/code&gt; endpoint).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native service discovery&lt;/strong&gt; — No static IP lists. Prometheus discovers targets from Kubernetes, Consul, or DNS automatically.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Prometheus Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│                    Prometheus Server                        │
│   ┌──────────────┐    ┌──────────────┐    ┌─────────────┐  │
│   │   Scraper    │    │    TSDB       │    │ Rule Engine │  │
│   │  (pull HTTP) │    │  (storage)   │    │  (alerts)   │  │
│   └──────┬───────┘    └──────────────┘    └──────┬──────┘  │
└──────────┼────────────────────────────────────────┼─────────┘
           │ scrape /metrics                        │ fire alerts
           ▼                                        ▼
┌─────────────────────┐                  ┌──────────────────────┐
│  Service Discovery  │                  │    Alertmanager      │
│  (K8s / Consul/DNS) │                  │  (dedup, group,      │
└─────────────────────┘                  │   notify: DingTalk / │
                                         │   WeCom / Email)     │
┌─────────────────────┐                  └──────────────────────┘
│    PushGateway      │ ← for short-lived jobs (batch, PHP scripts)
└─────────────────────┘
┌─────────────────────┐
│     Exporters       │ ← Node Exporter, Blackbox Exporter, etc.
└─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;PushGateway&lt;/strong&gt; exists specifically for short-lived processes (batch jobs, PHP scripts) that won't survive long enough to be scraped.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Prometheus Data Model
&lt;/h3&gt;

&lt;p&gt;Every metric is a combination of a &lt;strong&gt;name&lt;/strong&gt; + &lt;strong&gt;labels&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prometheus"&gt;&lt;code&gt;&lt;span class="n"&gt;negri_http_request_total&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"serviceA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"200"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;exported_service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"serviceB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/ping"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;negri_http_request_total&lt;/code&gt; — metric name (describes what it measures)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{client, code, exported_service, path}&lt;/code&gt; — labels (dimensions for filtering/aggregation)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Four Metric Types
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Computed By&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Counter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Server-side&lt;/td&gt;
&lt;td&gt;QPS, total requests (monotonically increasing)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;negri_http_request_total&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gauge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Client-side&lt;/td&gt;
&lt;td&gt;Instantaneous values, event flags (circuit breaker open/closed)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;degrade_events{event="eventBreakerOpenStatus"}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Histogram&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Server-side&lt;/td&gt;
&lt;td&gt;Latency percentiles (p90/p95/p99), response size distribution&lt;/td&gt;
&lt;td&gt;&lt;code&gt;negri_http_response_time_us_bucket{le="0.5"}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Client-side&lt;/td&gt;
&lt;td&gt;Precise percentiles, but less flexible at query time&lt;/td&gt;
&lt;td&gt;Similar to Histogram&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Counter vs Gauge:&lt;/strong&gt; If your value only goes up → use Counter (cheaper, server-side). If it goes up and down → use Gauge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Histogram vs Summary:&lt;/strong&gt; Histogram is more flexible (percentiles calculated at query time in Grafana). Summary is more precise but percentiles are fixed at instrumentation time.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Grafana Dashboard: What to Look At
&lt;/h3&gt;

&lt;p&gt;Istio ships with pre-built Grafana dashboards. Here's how to navigate them effectively.&lt;/p&gt;

&lt;h4&gt;
  
  
  Services Dashboard
&lt;/h4&gt;

&lt;p&gt;Key filter parameters:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;What It Means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Service&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The Kubernetes service name (e.g. &lt;code&gt;details.default.svc.cluster.local&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Client Workload Namespace&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The K8s namespace where the client lives&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Client Workload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The upstream caller — e.g. &lt;code&gt;productpage-v1&lt;/code&gt; calling &lt;code&gt;details&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Service Workload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The specific version of the service — e.g. &lt;code&gt;reviews-v1&lt;/code&gt;, &lt;code&gt;reviews-v2&lt;/code&gt;, &lt;code&gt;reviews-v3&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why &lt;code&gt;Client Workload&lt;/code&gt; matters:&lt;/strong&gt; Traditional microservice SDKs often struggle to reliably inject the caller's service name into metrics. Developers might hardcode the wrong name or copy-paste from another service. Istio eliminates this entirely — the control plane injects the caller identity automatically via the sidecar. No human error possible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Key panels in the dashboard:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;QPS&lt;/strong&gt; (client-side vs server-side) — client-side is more accurate as it includes network latency&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Success Rate&lt;/strong&gt; — percentage of non-5xx responses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency&lt;/strong&gt; — p50/p90/p99 breakdown&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Workload Dashboard
&lt;/h4&gt;

&lt;p&gt;The Workload dashboard adds a critical dimension: &lt;strong&gt;inbound vs outbound traffic&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;reviews-v3 Workload
├── INBOUND  ← traffic FROM productpage-v1
└── OUTBOUND ← traffic TO ratings.default.svc.cluster.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This dual-direction view is invaluable for root cause analysis. When &lt;code&gt;reviews-v3&lt;/code&gt; is slow, you can immediately see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is it slow because &lt;em&gt;incoming&lt;/em&gt; traffic is high? (upstream pressure)&lt;/li&gt;
&lt;li&gt;Or is it slow because &lt;em&gt;outgoing&lt;/em&gt; calls to &lt;code&gt;ratings&lt;/code&gt; are slow? (downstream dependency)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Part 2: Distributed Tracing with Jaeger
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Three Pillars of Observability — Compared
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Metrics  →  "Something is wrong with reviews-v3 (p99 latency spiked to 2s)"
Tracing  →  "The spike is caused by the ratings service call at step 4 of this specific request"
Logging  →  "Here's the exact SQL query and stack trace that caused it"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each tool answers a different question. Tracing is the bridge between "something is wrong" and "here's exactly why."&lt;/p&gt;

&lt;h3&gt;
  
  
  How Distributed Tracing Works (Dapper Model)
&lt;/h3&gt;

&lt;p&gt;Tracing originates from Google's &lt;strong&gt;Dapper&lt;/strong&gt; paper. The core concepts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TraceId: 5f1db306ef459b2f  (unique per request, generated at the gateway)
│
├── Span A  (SpanId: aaa, ParentSpanId: null)  ← root span (productpage)
│     │
│     ├── Span B  (SpanId: bbb, ParentSpanId: aaa)  ← details service call
│     │
│     └── Span C  (SpanId: ccc, ParentSpanId: aaa)  ← reviews service call
│           │
│           └── Span D  (SpanId: ddd, ParentSpanId: ccc)  ← ratings service call
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trace context is propagated via &lt;strong&gt;HTTP headers&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;Header&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x-request-id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unique request ID for log correlation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x-b3-traceid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;64-bit global trace identifier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x-b3-spanid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Current span position in the trace tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x-b3-parentspanid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Parent span (absent = root node)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x-b3-sampled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sampling flag (&lt;code&gt;1&lt;/code&gt; = record this trace)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  A Real Trace Record
&lt;/h3&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;"traceID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5f1db306ef459b2f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"spanID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5f1db306ef459b2f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parentSpanID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"operationName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/ping"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2065&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"startTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1609241265147010&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"process"&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;"serviceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"negri.sidecarserverlistener.myapp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tags"&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;"hostname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MacBook-Pro-3.local"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"ip"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"192.168.1.88"&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;"tags"&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;"http.method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"http.status_code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"200"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"http.url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/ping"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"peer.address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:8888"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"span.kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"server"&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;h3&gt;
  
  
  Jaeger Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application Code
     │ UDP
     ▼
┌──────────────┐     ┌──────────────────┐     ┌──────────────┐
│ jaeger-client│────▶│  jaeger-agent    │────▶│jaeger-       │
│ (SDK)        │     │  (per-host       │     │collector     │
└──────────────┘     │   daemon)        │     │(validate +   │
                     └──────────────────┘     │ process)     │
                                              └──────┬───────┘
                                                     │
                                                     ▼
                                             ┌──────────────┐
                                             │  jaeger-db   │
                                             │ (Cassandra / │
                                             │  Elasticsearch│
                                             └──────┬───────┘
                                                    │
                                                    ▼
                                             ┌──────────────┐
                                             │ jaeger-query │
                                             │ (UI + API)   │
                                             └──────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why jaeger-agent?&lt;/strong&gt; Same philosophy as Istio's sidecar — it offloads service discovery and routing complexity from the client SDK. The app just sends UDP to localhost and forgets about it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The One Thing Your Code Must Do
&lt;/h3&gt;

&lt;p&gt;Envoy automatically generates spans and propagates B3 headers to upstream services. &lt;strong&gt;But&lt;/strong&gt; — it cannot read the incoming headers and pass them downstream on your behalf. Your application code must forward the trace headers manually.&lt;/p&gt;

&lt;p&gt;Here's the pattern from the Bookinfo sample app (Python):&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="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/productpage&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@trace&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;front&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getForwardHeaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# extract + forward trace headers
&lt;/span&gt;    &lt;span class="n"&gt;details&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getProductDetails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# pass them downstream
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;getForwardHeaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="c1"&gt;# B3 headers — extracted automatically via OpenTracing library
&lt;/span&gt;    &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_current_span&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;carrier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;span_context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_HEADERS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;carrier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;carrier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;carrier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Other headers that must be forwarded manually
&lt;/span&gt;    &lt;span class="n"&gt;incoming_headers&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;x-request-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;x-ot-span-context&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;traceparent&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;tracestate&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;x-cloud-trace-context&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;grpc-trace-bin&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;user-agent&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;incoming_headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&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;val&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key insight:&lt;/strong&gt; Envoy handles span &lt;em&gt;creation&lt;/em&gt; and &lt;em&gt;injection&lt;/em&gt; automatically. Your app only needs to &lt;em&gt;forward&lt;/em&gt; the headers it receives. This is a much lighter instrumentation burden than traditional APM agents.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What Jaeger Shows You
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Trace List View&lt;/strong&gt; — All traces for a service, sortable by duration. Immediately surfaces the slowest requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trace Detail View&lt;/strong&gt; — Full waterfall of every span in a single request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;productpage  ──────────────────────────────  450ms
  details      ───  45ms
  reviews        ──────────────────  380ms
    ratings        ────────────  310ms  ← bottleneck identified
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;System Architecture View&lt;/strong&gt; — Auto-generated service dependency graph derived from trace data. No manual diagram maintenance needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary: Metrics vs Tracing — When to Use Which
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"Is the service healthy right now?"&lt;/td&gt;
&lt;td&gt;Metrics (Grafana dashboard)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Has latency been trending up this week?"&lt;/td&gt;
&lt;td&gt;Metrics (Prometheus query)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Why did &lt;em&gt;this specific request&lt;/em&gt; take 3 seconds?"&lt;/td&gt;
&lt;td&gt;Tracing (Jaeger)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Which service is the bottleneck in my call chain?"&lt;/td&gt;
&lt;td&gt;Tracing (Jaeger waterfall)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"What exact error did service X return at 14:32?"&lt;/td&gt;
&lt;td&gt;Logging (ELK)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The power of Istio is that &lt;strong&gt;you get all of this without modifying your application&lt;/strong&gt; — except for the minimal header forwarding shown above. The sidecar handles metric collection, span generation, and header injection automatically.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;💻 Explore the full implementation:&lt;br&gt;
&lt;a href="https://github.com/muzinan123/servicemesh" rel="noopener noreferrer"&gt;github.com/muzinan123/servicemesh&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>devops</category>
      <category>kubernetes</category>
      <category>microservices</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>Traffic Management in Istio: Circuit Breaking &amp; Rate Limiting with DestinationRule</title>
      <dc:creator>James Lee</dc:creator>
      <pubDate>Fri, 22 May 2026 10:15:40 +0000</pubDate>
      <link>https://forem.com/jamesli/traffic-management-in-istio-circuit-breaking-rate-limiting-with-destinationrule-1oim</link>
      <guid>https://forem.com/jamesli/traffic-management-in-istio-circuit-breaking-rate-limiting-with-destinationrule-1oim</guid>
      <description>&lt;p&gt;One of Istio's most powerful features is the ability to configure &lt;strong&gt;circuit breaking&lt;/strong&gt; and &lt;strong&gt;rate limiting&lt;/strong&gt; declaratively — without touching a single line of application code. Everything is controlled through a single CRD: &lt;code&gt;DestinationRule&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this article, I'll break down exactly how &lt;code&gt;connectionPool&lt;/code&gt; (rate limiting) and &lt;code&gt;outlierDetection&lt;/code&gt; (circuit breaking) work, with real YAML examples.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Entry Point: TrafficPolicy in DestinationRule
&lt;/h2&gt;

&lt;p&gt;Both circuit breaking and rate limiting are configured under the &lt;code&gt;trafficPolicy&lt;/code&gt; field of a &lt;code&gt;DestinationRule&lt;/code&gt;:&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;networking.istio.io/v1alpha3&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;DestinationRule&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-service-dr&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;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-service&lt;/span&gt;
  &lt;span class="na"&gt;trafficPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;connectionPool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;    &lt;span class="c1"&gt;# ← Rate limiting config&lt;/span&gt;
      &lt;span class="na"&gt;tcp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;maxConnections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
      &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;http1MaxPendingRequests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
        &lt;span class="na"&gt;http2MaxRequests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
    &lt;span class="na"&gt;outlierDetection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# ← Circuit breaking config&lt;/span&gt;
      &lt;span class="na"&gt;consecutiveErrors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;baseEjectionTime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
      &lt;span class="na"&gt;maxEjectionPercent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 1: Rate Limiting with &lt;code&gt;connectionPool&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;connectionPool&lt;/code&gt; controls &lt;strong&gt;how many concurrent connections and requests&lt;/strong&gt; are allowed to reach an upstream service. It has two sub-sections: &lt;code&gt;tcp&lt;/code&gt; and &lt;code&gt;http&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  TCP Settings
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxConnections&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Max number of HTTP1/TCP connections to the destination&lt;/td&gt;
&lt;td&gt;unlimited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;connectTimeout&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;TCP connection timeout&lt;/td&gt;
&lt;td&gt;10s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Important:&lt;/strong&gt; &lt;code&gt;maxConnections&lt;/code&gt; only limits &lt;strong&gt;HTTP/1.1 and TCP&lt;/strong&gt; connections. It does &lt;strong&gt;not&lt;/strong&gt; affect HTTP/2, because HTTP/2 multiplexes all requests over a single connection.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  HTTP Settings
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;http1MaxPendingRequests&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Max queued HTTP/1.1 requests waiting to be processed&lt;/td&gt;
&lt;td&gt;1024&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;http2MaxRequests&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Max concurrent HTTP/2 requests&lt;/td&gt;
&lt;td&gt;1024&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxRequestsPerConnection&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;How many requests can reuse one TCP connection. Set to &lt;code&gt;1&lt;/code&gt; to disable keepalive&lt;/td&gt;
&lt;td&gt;unlimited&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Full connectionPool Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;trafficPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;connectionPool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tcp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;maxConnections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
      &lt;span class="na"&gt;connectTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3s&lt;/span&gt;
    &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;http1MaxPendingRequests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
      &lt;span class="na"&gt;http2MaxRequests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
      &lt;span class="na"&gt;maxRequestsPerConnection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What this does:&lt;/strong&gt; Limits the service to 100 concurrent TCP connections, queues at most 100 pending HTTP/1.1 requests, and allows up to 1000 concurrent HTTP/2 requests. Each TCP connection can serve up to 10 requests before being recycled.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2: Circuit Breaking with &lt;code&gt;outlierDetection&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;outlierDetection&lt;/code&gt; implements the &lt;strong&gt;circuit breaker pattern&lt;/strong&gt; at the Envoy level. When a service instance starts returning errors, Istio automatically ejects it from the load balancing pool.&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request → Envoy → Load Balancer Pool
                   ├── Instance A (healthy) ✅
                   ├── Instance B (healthy) ✅
                   └── Instance C (5xx × 5) ❌ → Ejected for 30s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When Instance C is ejected, traffic is only routed to A and B. After &lt;code&gt;baseEjectionTime&lt;/code&gt;, Instance C gets a chance to re-enter the pool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration Fields
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;consecutiveErrors&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number of consecutive 5xx errors (502/503/504) before ejection&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;interval&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Time window for counting errors&lt;/td&gt;
&lt;td&gt;10s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;baseEjectionTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Minimum ejection duration. Actual time = &lt;code&gt;baseEjectionTime × ejection count&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;30s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxEjectionPercent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Max % of instances that can be ejected at once&lt;/td&gt;
&lt;td&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;minHealthPercent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;If healthy instances drop below this %, circuit breaking is &lt;strong&gt;disabled&lt;/strong&gt; entirely&lt;/td&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Full outlierDetection Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;trafficPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;outlierDetection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;consecutiveErrors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
    &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
    &lt;span class="na"&gt;baseEjectionTime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
    &lt;span class="na"&gt;maxEjectionPercent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
    &lt;span class="na"&gt;minHealthPercent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Key Design Decisions Worth Understanding
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Progressive Ejection Time
&lt;/h3&gt;

&lt;p&gt;The actual ejection time is not fixed — it grows with each ejection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1st ejection: 30s × 1 = 30s
2nd ejection: 30s × 2 = 60s
3rd ejection: 30s × 3 = 90s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is intentional: a repeatedly failing instance gets longer and longer timeouts, giving it more time to recover.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Safety Net: &lt;code&gt;maxEjectionPercent&lt;/code&gt; + &lt;code&gt;minHealthPercent&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;These two fields work together to prevent a cascade failure from taking down your entire service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;maxEjectionPercent: 10&lt;/code&gt;&lt;/strong&gt; — Even if 50 instances are all returning 5xx errors, only 10% will be ejected at any one time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;minHealthPercent: 50&lt;/code&gt;&lt;/strong&gt; — If healthy instances drop below 50%, Istio &lt;strong&gt;disables&lt;/strong&gt; outlier detection entirely and allows all instances (including unhealthy ones) to receive traffic.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why disable circuit breaking when too many instances are unhealthy?&lt;/strong&gt;&lt;br&gt;
Because at that point, the problem is likely systemic (e.g., a bad deployment, downstream dependency failure). Ejecting more instances would only make things worse. It's better to let all instances handle traffic and surface the real error.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Putting It All Together
&lt;/h2&gt;

&lt;p&gt;Here's a production-ready &lt;code&gt;DestinationRule&lt;/code&gt; combining both features:&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;networking.istio.io/v1alpha3&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;DestinationRule&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;reviews-dr&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;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reviews&lt;/span&gt;
  &lt;span class="na"&gt;trafficPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;connectionPool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;tcp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;maxConnections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
        &lt;span class="na"&gt;connectTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3s&lt;/span&gt;
      &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;http1MaxPendingRequests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
        &lt;span class="na"&gt;http2MaxRequests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
        &lt;span class="na"&gt;maxRequestsPerConnection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
    &lt;span class="na"&gt;outlierDetection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;consecutiveErrors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;baseEjectionTime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
      &lt;span class="na"&gt;maxEjectionPercent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
      &lt;span class="na"&gt;minHealthPercent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Summary
&lt;/h2&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;Config Field&lt;/th&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rate Limiting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;connectionPool.tcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Limit TCP connections&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rate Limiting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;connectionPool.http&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Limit concurrent HTTP requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Circuit Breaking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;outlierDetection.consecutiveErrors&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Eject on N consecutive errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Safety Net&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;outlierDetection.maxEjectionPercent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cap max ejected instances&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Safety Net&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;outlierDetection.minHealthPercent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Disable CB when cluster is too unhealthy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The beauty of Istio's approach: &lt;strong&gt;all of this happens at the proxy layer&lt;/strong&gt;. Your application code doesn't need to implement Hystrix, Resilience4j, or any circuit breaker library. The infrastructure handles it.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;💻 Explore the full implementation:&lt;br&gt;
&lt;a href="https://github.com/muzinan123/servicemesh" rel="noopener noreferrer"&gt;github.com/muzinan123/servicemesh&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📖 Next in this series: Full Observability in Istio: Metrics + Distributed Tracing&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>devops</category>
      <category>kubernetes</category>
      <category>microservices</category>
      <category>networking</category>
    </item>
    <item>
      <title>Istio &amp; Envoy Service Mesh Architecture: How the Control Plane and Data Plane Work Together</title>
      <dc:creator>James Lee</dc:creator>
      <pubDate>Fri, 22 May 2026 10:14:51 +0000</pubDate>
      <link>https://forem.com/jamesli/istio-envoy-service-mesh-architecture-how-the-control-plane-and-data-plane-work-together-2nd6</link>
      <guid>https://forem.com/jamesli/istio-envoy-service-mesh-architecture-how-the-control-plane-and-data-plane-work-together-2nd6</guid>
      <description>&lt;p&gt;If you've worked with Istio, you've probably heard terms like "control plane," "data plane," "Pilot," and "Envoy sidecar." But how do they actually fit together? In this article, I'll walk through the full architecture — from how Pilot discovers services to how a client request is processed inside Envoy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: How Pilot and Envoy Work Together
&lt;/h2&gt;

&lt;p&gt;The Istio control plane component &lt;strong&gt;Pilot&lt;/strong&gt; is responsible for bridging Kubernetes and Envoy. Here's the three-step flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────┐
│                    API Server                       │
└──────────────────────┬──────────────────────────────┘
                       │ 1. Service discovery
                       │    (Services + Endpoints via client-go Informer)
                       │ 2. Fetch Istio CRDs
                       │    (VirtualService, DestinationRule, etc.)
                       ▼
┌─────────────────────────────────────────────────────┐
│                   Istio Pilot                       │
│                                                     │
│  Convert: Endpoints + governance policies           │
│        → Envoy-compatible xDS format                │
└──────────────────────┬──────────────────────────────┘
                       │ 3. Push via xDS
                       ▼
┌─────────────────────────────────────────────────────┐
│                  Envoy Sidecar                      │
│         (Listener → Route → Cluster → Endpoint)    │
└─────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 1 — Service Discovery:&lt;/strong&gt;&lt;br&gt;
Pilot uses the &lt;code&gt;client-go&lt;/code&gt; Informer to watch the Kubernetes API Server, collecting all &lt;code&gt;Service&lt;/code&gt; and &lt;code&gt;Endpoints&lt;/code&gt; resources across the cluster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Policy Discovery:&lt;/strong&gt;&lt;br&gt;
Pilot also watches for user-defined Istio CRD objects: &lt;code&gt;VirtualService&lt;/code&gt;, &lt;code&gt;DestinationRule&lt;/code&gt;, &lt;code&gt;Gateway&lt;/code&gt;, etc. These define the traffic governance policies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — xDS Push:&lt;/strong&gt;&lt;br&gt;
Pilot converts the combined service topology and governance policies into Envoy's native xDS format, then pushes the config to each Envoy sidecar via gRPC streaming.&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 2: The Four Core Resources in Envoy
&lt;/h2&gt;

&lt;p&gt;Once config is pushed to Envoy, how does a client request actually get processed? It flows through four core resource types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client Request
     │
     ▼
┌──────────┐     ┌──────────┐     ┌──────────┐     ┌────────────┐
│ Listener │────▶│  Route   │────▶│ Cluster  │──LB▶│  Endpoint  │
│  (LDS)   │     │  (RDS)   │     │  (CDS)   │     │   (EDS)    │
└──────────┘     └──────────┘     └──────────┘     └────────────┘
     │                                                     │
L3/L4 Filters                                     Upstream Service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1. Listener (LDS)
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;Listener&lt;/strong&gt; is a port that Envoy opens to accept incoming connections. Multiple Listeners are fully isolated from each other. Beyond port binding, each Listener is configured with L3/L4 filters.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Config is managed via &lt;strong&gt;LDS&lt;/strong&gt; (Listener Discovery Service).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. Cluster (CDS + EDS)
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;Cluster&lt;/strong&gt; is the abstraction for an upstream service. Every upstream service maps to exactly one Cluster. Cluster config includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connection timeout&lt;/li&gt;
&lt;li&gt;Connection pool settings&lt;/li&gt;
&lt;li&gt;Load balancing policy&lt;/li&gt;
&lt;li&gt;Health check config&lt;/li&gt;
&lt;li&gt;Endpoint list&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Config is managed via &lt;strong&gt;CDS&lt;/strong&gt; (Cluster Discovery Service) + &lt;strong&gt;EDS&lt;/strong&gt; (Endpoint Discovery Service).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Route (RDS)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Route&lt;/strong&gt; is the bridge between Listeners and Clusters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listener receives the request&lt;/li&gt;
&lt;li&gt;Route decides &lt;em&gt;which Cluster&lt;/em&gt; to forward it to&lt;/li&gt;
&lt;li&gt;Route also handles: Virtual Host definitions, HTTP header manipulation (add/remove/modify), timeout &amp;amp; retry policies&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Config is managed via &lt;strong&gt;RDS&lt;/strong&gt; (Route Discovery Service).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  4. Filter (Envoy Filter)
&lt;/h3&gt;

&lt;p&gt;Filters are Envoy's &lt;strong&gt;plugin mechanism&lt;/strong&gt; — they allow powerful extensions without modifying source code. There are three layers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Filter Layer&lt;/th&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;th&gt;Examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Listener Filter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pre-routing, L3/L4&lt;/td&gt;
&lt;td&gt;TLS Inspector, HTTP Inspector, Original Destination&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Network Filter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;L3/L4 connection handling&lt;/td&gt;
&lt;td&gt;Dubbo proxy, Kafka filter, MySQL proxy, Redis proxy, HTTP Connection Manager&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HTTP Filter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;L7 HTTP traffic&lt;/td&gt;
&lt;td&gt;Route matching, Health check, Lua, CSRF, VHDS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key insight:&lt;/strong&gt; The &lt;strong&gt;HTTP Connection Manager (HCM)&lt;/strong&gt; is itself a special Network Filter that manages all HTTP Filters. This layered design is what gives Envoy the ability to support virtually any protocol — and even perform protocol conversion.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Full Architecture: Putting It All Together
&lt;/h2&gt;

&lt;p&gt;Here's how the complete picture looks — from API Server down to upstream services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────────┐
│                         API Server                               │
└────────────────────────────┬─────────────────────────────────────┘
                             │ Services, Endpoints, Istio CRDs
                             ▼
┌──────────────────────────────────────────────────────────────────┐
│                        Istio Pilot                               │
│  ① Service discovery    ② Fetch CRDs    ③ Convert &amp;amp; push xDS    │
└────────────────────────────┬─────────────────────────────────────┘
                             │ xDS (gRPC streaming)
                             ▼
┌──────────────────────────────────────────────────────────────────┐
│                          Envoy                                   │
│                                                                  │
│  Listener0 ┐                  Cluster0 ┐         Endpoint0      │
│  Listener1 ├──Route──────────▶Cluster1 ├──LB────▶Endpoint1      │
│  Listener2 ┘                  Cluster2 ┘         Endpoint2      │
│                                                  Endpoint3      │
│                                                                  │
│  [Listener Filter] → [Network Filter] → [HTTP Filter]           │
└──────────────────────────────────────────────────────────────────┘
                             │
                             ▼
                   Upstream Application Services
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Why This Architecture Matters
&lt;/h2&gt;

&lt;p&gt;This design gives Istio several powerful properties:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Zero-touch config updates&lt;/strong&gt; — Envoy never needs to restart. All config changes are pushed via xDS streaming.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protocol agnostic&lt;/strong&gt; — Through Network Filters, Envoy natively supports HTTP, gRPC, Dubbo, Kafka, MySQL, Redis, and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy separation&lt;/strong&gt; — Traffic governance rules (VirtualService, DestinationRule) live in the control plane. The data plane (Envoy) just executes them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensibility&lt;/strong&gt; — Custom Envoy Filters allow teams to add any behavior (auth, rate limiting, tracing) without touching application code.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pilot&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Discovers services + policies, converts to xDS, pushes to Envoy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Envoy Listener&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Accepts client connections on configured ports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Envoy Route&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Decides which Cluster handles each request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Envoy Cluster&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Abstracts upstream services with LB + health check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Envoy Endpoint&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The actual upstream instance IP:port&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Envoy Filter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Plugin mechanism for L4/L7 traffic manipulation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Understanding this architecture is the foundation for everything else in Istio — circuit breaking, canary releases, observability. They all build on top of these primitives.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;💻 Explore the full implementation:&lt;br&gt;
&lt;a href="https://github.com/muzinan123/servicemesh" rel="noopener noreferrer"&gt;github.com/muzinan123/servicemesh&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📖 Next in this series: Traffic Management in Istio: Circuit Breaking &amp;amp; Rate Limiting&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>architecture</category>
      <category>kubernetes</category>
      <category>microservices</category>
      <category>networking</category>
    </item>
    <item>
      <title>xDS Protocol Deep Dive: The Universal Control Plane API Behind Envoy and Istio</title>
      <dc:creator>James Lee</dc:creator>
      <pubDate>Fri, 22 May 2026 10:13:12 +0000</pubDate>
      <link>https://forem.com/jamesli/xds-protocol-deep-dive-the-universal-control-plane-api-behind-envoy-and-istio-2de9</link>
      <guid>https://forem.com/jamesli/xds-protocol-deep-dive-the-universal-control-plane-api-behind-envoy-and-istio-2de9</guid>
      <description>&lt;p&gt;When we talk about Istio or Envoy, we often hear terms like "dynamic configuration" and "control plane push." But what exactly is the underlying protocol that makes all of this work? The answer is &lt;strong&gt;xDS&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this article, I'll do a deep dive into the xDS protocol — what it is, how it works, and why it matters beyond just Service Mesh.&lt;/p&gt;




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

&lt;p&gt;xDS is a family of &lt;strong&gt;discovery service APIs&lt;/strong&gt; that allow a data plane proxy (like Envoy) to dynamically fetch configuration from a management server — without any restart or file reload.&lt;/p&gt;

&lt;p&gt;The "x" in xDS is a wildcard. It covers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;API&lt;/th&gt;
&lt;th&gt;Full Name&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LDS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Listener Discovery Service&lt;/td&gt;
&lt;td&gt;Dynamically manage listeners (ports)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RDS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Route Discovery Service&lt;/td&gt;
&lt;td&gt;Dynamically manage routing rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CDS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cluster Discovery Service&lt;/td&gt;
&lt;td&gt;Dynamically manage upstream clusters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EDS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Endpoint Discovery Service&lt;/td&gt;
&lt;td&gt;Dynamically manage cluster endpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SDS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Secret Discovery Service&lt;/td&gt;
&lt;td&gt;Dynamically manage TLS certificates&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key insight:&lt;/strong&gt; xDS is not just for Service Mesh. gRPC also uses xDS for service discovery. It defines a universal, extensible control API for microservices — any configuration can be resolved through discovery.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Four Core Resources in Envoy
&lt;/h2&gt;

&lt;p&gt;Each xDS type corresponds to a specific resource type. The type is stored in the &lt;code&gt;TypeUrl&lt;/code&gt; field of every &lt;code&gt;DiscoveryRequest&lt;/code&gt; and &lt;code&gt;DiscoveryResponse&lt;/code&gt;, in the format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type.googleapis.com/&amp;lt;resource type&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example: &lt;code&gt;type.googleapis.com/envoy.api.v2.Cluster&lt;/code&gt; means this is a CDS (Cluster) resource.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. LDS — Listener Discovery Service
&lt;/h3&gt;

&lt;p&gt;A Listener is a port that Envoy opens to accept incoming connections. It can be configured with L3/L4 filters.&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"filter_chains"&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;"listener_filters"&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;"traffic_direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"access_log"&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;h3&gt;
  
  
  2. RDS — Route Discovery Service
&lt;/h3&gt;

&lt;p&gt;Routes act as the bridge between Listeners and Clusters. They define traffic distribution rules, virtual hosts, header manipulation, timeouts, and retries.&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"virtual_hosts"&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;"response_headers_to_add"&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;"request_headers_to_add"&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;"validate_clusters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;h3&gt;
  
  
  3. CDS — Cluster Discovery Service
&lt;/h3&gt;

&lt;p&gt;A Cluster is an abstraction of an upstream service. It includes load balancing policy, health checks, circuit breaker config, and TLS settings.&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"eds_cluster_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"lb_policy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"health_checks"&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;"circuit_breakers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"outlier_detection"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;h3&gt;
  
  
  4. EDS — Endpoint Discovery Service
&lt;/h3&gt;

&lt;p&gt;EDS is the actual service discovery layer. It returns the live endpoints (IP + port) for a given cluster.&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;"cluster_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"endpoints"&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;"policy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;h3&gt;
  
  
  5. SDS — Secret Discovery Service
&lt;/h3&gt;

&lt;p&gt;SDS enables &lt;strong&gt;dynamic TLS certificate rotation&lt;/strong&gt; without restarting Envoy. In early Istio versions, certificate updates required a hot restart — SDS eliminated that entirely.&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"tls_certificate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"validation_context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;h2&gt;
  
  
  How xDS Works: gRPC Streaming Subscription
&lt;/h2&gt;

&lt;p&gt;Early xDS used REST/JSON polling. Starting from v2, it switched to &lt;strong&gt;gRPC bidirectional streaming&lt;/strong&gt;, which provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lower latency for config updates&lt;/li&gt;
&lt;li&gt;Better performance under high churn&lt;/li&gt;
&lt;li&gt;Native support for ACK/NACK flow control&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Request Flow for a Typical HTTP Route
&lt;/h3&gt;

&lt;p&gt;The API request order follows the dependency chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LDS → RDS → CDS → EDS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Envoy fetches &lt;strong&gt;Listeners&lt;/strong&gt; (LDS) to know which ports to open&lt;/li&gt;
&lt;li&gt;From the Listener config, it gets the &lt;strong&gt;Route&lt;/strong&gt; name → fetches Routes (RDS)&lt;/li&gt;
&lt;li&gt;Routes reference &lt;strong&gt;Clusters&lt;/strong&gt; → fetches Clusters (CDS)&lt;/li&gt;
&lt;li&gt;Clusters need live &lt;strong&gt;Endpoints&lt;/strong&gt; → fetches Endpoints (EDS)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Full Subscription vs. Delta (Incremental) Subscription
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Full (SotW)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Management server returns all subscribed resources on every update&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Delta (Incremental)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only changed resources are sent — much more efficient at scale&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  xDS Protocol Deep Dive
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Request Message Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version_info&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;          &lt;span class="c1"&gt;# empty = first request&lt;/span&gt;
&lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;envoy&lt;/span&gt;               &lt;span class="c1"&gt;# unique node identifier (e.g. hostname)&lt;/span&gt;
&lt;span class="na"&gt;resource_names&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;foo&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bar&lt;/span&gt;
&lt;span class="na"&gt;type_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;type.googleapis.com/envoy.api.v2.ClusterLoadAssignment&lt;/span&gt;
&lt;span class="na"&gt;response_nonce&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;        &lt;span class="c1"&gt;# empty = first request&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;version_info&lt;/code&gt;&lt;/strong&gt;: empty on first request; subsequent requests echo the server's version&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;node.id&lt;/code&gt;&lt;/strong&gt;: only required on the first message per stream&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;resource_names&lt;/code&gt;&lt;/strong&gt;: the specific resources being subscribed to&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;response_nonce&lt;/code&gt;&lt;/strong&gt;: used to correlate ACK/NACK with a specific server push&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Response Message Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version_info&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;X&lt;/span&gt;
&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;foo ClusterLoadAssignment proto encoding&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bar ClusterLoadAssignment proto encoding&lt;/span&gt;
&lt;span class="na"&gt;type_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;type.googleapis.com/envoy.api.v2.ClusterLoadAssignment&lt;/span&gt;
&lt;span class="na"&gt;nonce&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ACK and NACK
&lt;/h2&gt;

&lt;p&gt;After receiving a push from the management server, Envoy responds with either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;ACK&lt;/strong&gt;: Config applied successfully → sends back the &lt;strong&gt;new&lt;/strong&gt; &lt;code&gt;version_info&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;NACK&lt;/strong&gt;: Config failed to apply → sends back the &lt;strong&gt;old&lt;/strong&gt; &lt;code&gt;version_info&lt;/code&gt; with an error detail&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives the control plane full visibility into whether each Envoy instance has successfully adopted a new config.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resource Update &amp;amp; The Nonce Problem
&lt;/h2&gt;

&lt;p&gt;Here's where it gets interesting. Consider this scenario:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Envoy subscribes to cluster &lt;code&gt;foo&lt;/code&gt; (version X, nonce A)&lt;/li&gt;
&lt;li&gt;Management server pushes a new version Y (nonce B) because &lt;code&gt;foo&lt;/code&gt;'s endpoints changed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;At the same time&lt;/strong&gt;, Envoy wants to add a new subscription to cluster &lt;code&gt;bar&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If Envoy sends a new &lt;code&gt;DiscoveryRequest&lt;/code&gt; with &lt;code&gt;version_info=X&lt;/code&gt; and &lt;code&gt;resource_names=[foo, bar]&lt;/code&gt;, the management server might misinterpret this as a &lt;strong&gt;NACK for version Y&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution: Nonce&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The nonce uniquely identifies each push. Envoy's new subscription request carries &lt;code&gt;nonce=A&lt;/code&gt; (from its last ACK), while the version Y push has &lt;code&gt;nonce=B&lt;/code&gt;. The management server can distinguish between them unambiguously.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Istio's pragmatic approach:&lt;/strong&gt; Istio's control plane (Pilot) doesn't strictly follow the nonce/version_info spec. Instead, it checks whether the &lt;code&gt;resource_names&lt;/code&gt; (Clusters list) has actually changed. If yes, it treats the request as a resource update rather than ACK/NACK. Simpler and easier to reason about.&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;p&gt;xDS is the backbone of Envoy's dynamic configuration system. Understanding it is essential for anyone working with Istio, Envoy-based gateways, or building custom control planes.&lt;/p&gt;

&lt;p&gt;Key takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LDS → RDS → CDS → EDS&lt;/strong&gt; is the standard dependency chain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;gRPC streaming&lt;/strong&gt; replaced REST polling for real-time, low-latency updates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nonce&lt;/strong&gt; solves the ACK/NACK ambiguity problem in concurrent update scenarios&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SDS&lt;/strong&gt; enables zero-downtime certificate rotation&lt;/li&gt;
&lt;li&gt;xDS is &lt;strong&gt;not Istio-specific&lt;/strong&gt; — gRPC and other frameworks use it too&lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;💻 Explore the full Istio + Envoy implementation:&lt;br&gt;
&lt;a href="https://github.com/muzinan123/servicemesh" rel="noopener noreferrer"&gt;github.com/muzinan123/servicemesh&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📖 Next in this series: Istio &amp;amp; Envoy Service Mesh Architecture&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>api</category>
      <category>distributedsystems</category>
      <category>microservices</category>
      <category>networking</category>
    </item>
    <item>
      <title>client-go Deep Dive: Operator in Practice — Building a Canary Release Controller</title>
      <dc:creator>James Lee</dc:creator>
      <pubDate>Tue, 19 May 2026 10:10:38 +0000</pubDate>
      <link>https://forem.com/jamesli/client-go-deep-dive-operator-in-practice-building-a-canary-release-controller-1pia</link>
      <guid>https://forem.com/jamesli/client-go-deep-dive-operator-in-practice-building-a-canary-release-controller-1pia</guid>
      <description>&lt;p&gt;In the previous article we defined the Canary CRD. Now we build the &lt;strong&gt;Operator&lt;/strong&gt;: the controller that watches Canary resources and drives the actual release process. This is the final article in the series — everything we've covered comes together here.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. What Is an Operator?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Operator = CRD (schema) + Controller (reconciliation logic)

┌──────────────────────────────────────────────────────┐
│  Kubernetes Controller Manager                       │
│  manages built-in controllers:                       │
│  DeploymentController, ReplicaSetController, ...     │
└──────────────────────────────────────────────────────┘
                    +
┌──────────────────────────────────────────────────────┐
│  Your Operator                                       │
│  = CRD (Canary) + CanaryController                  │
│  encodes domain knowledge:                           │
│  "how to safely roll out a new version in batches"   │
└──────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Operator = a Kubernetes extension that solves domain-specific problems the platform itself doesn't know how to solve.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Project Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;canary-controller/
├── main.go                          ← controller entrypoint
├── go.mod
├── manifests/
│   └── crd-canary.yaml              ← CRD definition (Part 8)
└── pkg/
    ├── apis/
    │   └── canarycontroller/
    │       ├── register.go          ← GroupName constant
    │       └── v1alpha1/
    │           ├── doc.go           ← code-gen annotations
    │           ├── types.go         ← Canary/CanarySpec/CanaryStatus
    │           └── register.go      ← register types with runtime.Scheme
    ├── controllers/
    │   └── canary_controller.go     ← all reconciliation logic
    ├── generated/                   ← auto-generated by code-generator
    │   ├── clientset/               ← typed Canary clientset
    │   ├── informers/               ← typed Canary informer
    │   └── listers/                 ← typed Canary lister
    └── signals/                     ← OS signal handling (SIGTERM/SIGINT)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Generating the Typed Client Code
&lt;/h2&gt;

&lt;p&gt;The built-in &lt;code&gt;kubernetes.Clientset&lt;/code&gt; only supports built-in resources. For your CRD, you need a generated typed client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/kubernetes/code-generator &lt;span class="nv"&gt;$GOPATH&lt;/span&gt;/src/k8s.io/code-generator

&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$GOPATH&lt;/span&gt;/src/k8s.io/code-generator &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./generate-groups.sh all &lt;span class="se"&gt;\&lt;/span&gt;
  canary-controller/pkg/client &lt;span class="se"&gt;\ &lt;/span&gt;     ← output
  canary-controller/pkg/apis &lt;span class="se"&gt;\ &lt;/span&gt;       ← input: your types
  canarycontroller:v1alpha1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Generated output&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zz_generated.deepcopy.go&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;DeepCopy()&lt;/code&gt; for all types&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generated/clientset/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;CanarycontrollerV1alpha1().Canaries(ns)&lt;/code&gt; — typed CRUD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generated/informers/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Typed &lt;code&gt;CanaryInformer&lt;/code&gt; with &lt;code&gt;Lister()&lt;/code&gt; and &lt;code&gt;HasSynced()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generated/listers/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;CanaryLister&lt;/code&gt; — fast local cache queries&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  4. Controller Struct &amp;amp; Wiring
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Controller&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;kubeclientset&lt;/span&gt;   &lt;span class="n"&gt;kubernetes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Interface&lt;/span&gt;   &lt;span class="c"&gt;// for built-in resources (Deployment)&lt;/span&gt;
    &lt;span class="n"&gt;canaryclientset&lt;/span&gt; &lt;span class="n"&gt;clientset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Interface&lt;/span&gt;    &lt;span class="c"&gt;// for Canary resources (generated)&lt;/span&gt;

    &lt;span class="n"&gt;deploymentsLister&lt;/span&gt; &lt;span class="n"&gt;appslisters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeploymentLister&lt;/span&gt;
    &lt;span class="n"&gt;deploymentsSynced&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InformerSynced&lt;/span&gt;
    &lt;span class="n"&gt;canariesLister&lt;/span&gt;    &lt;span class="n"&gt;listers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CanaryLister&lt;/span&gt;
    &lt;span class="n"&gt;canariesSynced&lt;/span&gt;    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InformerSynced&lt;/span&gt;

    &lt;span class="n"&gt;workqueue&lt;/span&gt; &lt;span class="n"&gt;workqueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RateLimitingInterface&lt;/span&gt;
    &lt;span class="n"&gt;recorder&lt;/span&gt;  &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventRecorder&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;NewController&lt;/code&gt;, two event subscriptions are registered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;① Canary Add/Update  → enqueueCanary()  → workqueue.Add(key)
  Direct: user changed Canary spec → reconcile immediately

② Deployment Add/Update/Delete → handleObject()
  → find owning Canary by name prefix → enqueueCanary()
  Indirect: managed Deployment changed state → re-check Canary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Run → Worker → syncHandler
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;controller.Run(threadiness=2, stopCh)
     │
     ├── cache.WaitForCacheSync()     ← block until Indexer ready
     │
     └── 2× goroutine: runWorker()
             └── processNextWorkItem()
                   ├── workqueue.Get(key)
                   ├── syncHandler(key)
                   │     ├── OK  → workqueue.Forget(key)
                   │     └── ERR → workqueue.AddRateLimited(key)  ← backoff retry
                   └── workqueue.Done(key)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;syncHandler&lt;/code&gt; is the reconciliation core — it reads the Canary spec and routes to the correct release strategy:&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;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;syncHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// ① Fetch from local cache — no API Server call&lt;/span&gt;
    &lt;span class="n"&gt;canary&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;canariesLister&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Canaries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// ② Route to release strategy&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;canary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Spec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"NormalDeploy"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;normalDeploy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"CanaryDeploy"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;firstCanaryDeploy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;or&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notFirstCanaryDeploy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"CanaryRollback"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;canaryRollback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// ③ Update status + emit Event&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;updateCanaryStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;deployment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recorder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;corev1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventTypeNormal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SuccessSynced&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&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;h2&gt;
  
  
  6. The Three Release Strategies
&lt;/h2&gt;

&lt;h3&gt;
  
  
  NormalDeploy — Rolling Update
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deployment exists?
├── No  → Create
└── Yes → image / replicas / CPU / memory drifted? → Update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Standard Kubernetes rolling update. No batching, no pause. The controller simply ensures the Deployment matches what's declared in the Canary spec.&lt;/p&gt;




&lt;h3&gt;
  
  
  CanaryDeploy — Batched Release
&lt;/h3&gt;

&lt;p&gt;Splits the rollout into N batches. &lt;strong&gt;Batch 1 always pauses&lt;/strong&gt; for human approval; subsequent batches auto-advance (when &lt;code&gt;pauseType=First&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Example: 4 replicas, 2 batches, pauseType=First

Start:    [v1][v1][v1][v1]   old=4, new=0

Batch 1:  [v2][v1][v1][v1]   old=3, new=1
               │
               └── PAUSE — wait for: kubectl patch canary ... currentBatch=2

Batch 2:  [v2][v2][v2][v2]   old=0, new=4  → old Deployment deleted ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Replica calculation per batch:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;everyAddReplicas = round(totalReplicas / totalBatches)

batch N target replicas = 1 + (N-1) × everyAddReplicas
final batch             = totalReplicas (full rollout)

old replicas = totalReplicas - new.AvailableReplicas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The controller continuously reconciles both Deployments — if anything drifts (pod crash, manual edit), the next reconcile loop corrects it automatically.&lt;/p&gt;




&lt;h3&gt;
  
  
  CanaryRollback — Reverse the Canary
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rollback type?
├── NormalDeploy rollback:
│     old.Name == new.Name → just update image back, no second Deployment
│
└── CanaryDeploy rollback:
      Restore old version replicas while draining new version
      new.AvailableReplicas → 0 → delete new Deployment ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Status Reporting: updateCanaryStatus
&lt;/h2&gt;

&lt;p&gt;After every reconcile, the controller updates the Canary's &lt;code&gt;status&lt;/code&gt; subresource to reflect real-time progress:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CanaryDeploy:
  batch N running  → status.info["batchNStatus"] = "Ing"
  batch N complete → status.info["batchNStatus"] = "Finished"
  availableReplicas updated on every loop

CanaryRollback:
  old Deployment still exists → status.info["rollbackStatus"] = "Ing"
  old Deployment deleted      → status.info["rollbackStatus"] = "Finished"

NormalDeploy:
  no status update needed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Always &lt;code&gt;DeepCopy()&lt;/code&gt; before mutating&lt;/strong&gt; — the object from Lister is a read-only reference to the Indexer cache. Modifying it directly corrupts the local cache.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;canaryCopy&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;canary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeepCopy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c"&gt;// ✅ safe to mutate&lt;/span&gt;
&lt;span class="n"&gt;canaryCopy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Finished"&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;canaryclientset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CanarycontrollerV1alpha1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;Canaries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UpdateStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canaryCopy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  8. Complete Execution Flow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
  &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;NewController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kubeclientset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;canaryclientset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;deployInformer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;canaryInformer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;AddEventHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Canary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;enqueueCanary&lt;/span&gt;
        &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;AddEventHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Deployment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;handleObject&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;enqueueCanary&lt;/span&gt;

&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;Reflector&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Watch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Deployment&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Canary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitForCacheSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;wait&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Indexer&lt;/span&gt; &lt;span class="n"&gt;fully&lt;/span&gt; &lt;span class="n"&gt;populated&lt;/span&gt;

&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;syncHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tech-prod/go-hello-canary"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="err"&gt;│&lt;/span&gt;
        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;canariesLister&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;        &lt;span class="err"&gt;←&lt;/span&gt; &lt;span class="n"&gt;Indexer&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;API&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="n"&gt;NormalDeploy&lt;/span&gt;   &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;Create&lt;/span&gt; &lt;span class="n"&gt;or&lt;/span&gt; &lt;span class="n"&gt;Update&lt;/span&gt; &lt;span class="n"&gt;Deployment&lt;/span&gt;
        &lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="n"&gt;CanaryDeploy&lt;/span&gt;   &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;Batch&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PAUSE&lt;/span&gt;
        &lt;span class="err"&gt;│&lt;/span&gt;                      &lt;span class="n"&gt;Batch&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DELETE&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;
        &lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="n"&gt;CanaryRollback&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;drain&lt;/span&gt; &lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;restore&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;
        &lt;span class="err"&gt;│&lt;/span&gt;
        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;updateCanaryStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;        &lt;span class="err"&gt;←&lt;/span&gt; &lt;span class="n"&gt;PATCH&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;
        &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;recorder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SuccessSynced&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  9. Key Design Principles
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Principle&lt;/th&gt;
&lt;th&gt;How&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Never mutate cache objects&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Always &lt;code&gt;DeepCopy()&lt;/code&gt; before modifying&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Read cache, write API&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Lister.Get()&lt;/code&gt; for reads; &lt;code&gt;clientset.Update()&lt;/code&gt; for writes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Idempotent reconciliation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Every loop checks actual vs desired — safe to re-run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ownership&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;OwnerReferences&lt;/code&gt; ensures Deployments are GC'd with their Canary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Error → retry&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;workqueue.AddRateLimited(key)&lt;/code&gt; — exponential backoff on failure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Series Complete 🎉
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Article&lt;/th&gt;
&lt;th&gt;Key concept&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Informer&lt;/td&gt;
&lt;td&gt;List/Watch, SharedInformerFactory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Reflector&lt;/td&gt;
&lt;td&gt;ListerWatcher, ListAndWatch, ResourceVersion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;DeltaFIFO&lt;/td&gt;
&lt;td&gt;queue+items, produce/consume, HandleDeltas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Indexer&lt;/td&gt;
&lt;td&gt;ThreadSafeMap, IndexFunc, ByIndex&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;WorkQueue&lt;/td&gt;
&lt;td&gt;Deduplication, Exponential Backoff, Token Bucket&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;EventBroadcaster&lt;/td&gt;
&lt;td&gt;Event resource, Recorder, Sink&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Controller (internal)&lt;/td&gt;
&lt;td&gt;Run, processLoop, WaitForCacheSync&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;CRD&lt;/td&gt;
&lt;td&gt;Schema, Go types, spec/status contract&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Operator in Practice&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Full canary release controller end-to-end&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;em&gt;Thank you for following the series. If you found it useful, share it with your team!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;📦 Source Code: &lt;a href="https://github.com/muzinan123/operator" rel="noopener noreferrer"&gt;github.com/muzinan123/operator&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>go</category>
      <category>kubernetes</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>client-go Deep Dive: CRD — Extending the Kubernetes API with Custom Resources</title>
      <dc:creator>James Lee</dc:creator>
      <pubDate>Tue, 19 May 2026 10:10:13 +0000</pubDate>
      <link>https://forem.com/jamesli/client-go-deep-dive-crd-extending-the-kubernetes-api-with-custom-resources-5cc3</link>
      <guid>https://forem.com/jamesli/client-go-deep-dive-crd-extending-the-kubernetes-api-with-custom-resources-5cc3</guid>
      <description>&lt;p&gt;In the previous seven articles we've thoroughly explored the Informer framework — Reflector, DeltaFIFO, Indexer, WorkQueue, EventBroadcaster, and the internal Controller. Now we shift from framework internals to &lt;strong&gt;application development&lt;/strong&gt;: building your own Kubernetes extensions with &lt;strong&gt;CRD&lt;/strong&gt; and &lt;strong&gt;Operator&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This article covers CRD — the foundation. The next article will build the Operator (controller) on top of it.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Kubernetes Declarative Model
&lt;/h2&gt;

&lt;p&gt;Before defining a CRD, it's worth understanding &lt;em&gt;why&lt;/em&gt; CRDs exist.&lt;/p&gt;

&lt;p&gt;Kubernetes is built on a &lt;strong&gt;declarative model&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│               Kubernetes Declarative Model                  │
│                                                             │
│  User declares desired state:                               │
│    "I want 3 replicas of nginx running"                     │
│                          │                                  │
│                          ▼                                  │
│  API Server stores it in etcd                               │
│                          │                                  │
│                          ▼                                  │
│  Controller Manager watches for drift:                      │
│    actual state ≠ desired state → take action               │
│                          │                                  │
│                          ▼                                  │
│  Actual state converges to desired state                    │
│  (user never specifies HOW — only WHAT)                     │
└─────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Built-in resources (Deployment, StatefulSet, DaemonSet, Service, Ingress, ConfigMap…) cover most use cases. But when they don't, Kubernetes provides two extension mechanisms:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;What it provides&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;CRD&lt;/strong&gt; (Custom Resource Definition)&lt;/td&gt;
&lt;td&gt;A new resource type — defines the schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Operator&lt;/strong&gt; (Custom Controller)&lt;/td&gt;
&lt;td&gt;The reconciliation logic — watches the CRD and acts on it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;CRD = the "what". Operator = the "how".&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Anatomy of a CRD YAML
&lt;/h2&gt;

&lt;p&gt;Here's a complete CRD definition for a canary deployment resource:&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;apiextensions.k8s.io/v1beta1&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;CustomResourceDefinition&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Format: {plural}.{group}&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;canaries.canarycontroller.tech.com&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api-approved.kubernetes.io"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://github.com/kubernetes/kubernetes/pull/78458"&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;# API group — appears in REST path: /apis/{group}/{version}&lt;/span&gt;
  &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;canarycontroller.tech.com&lt;/span&gt;

  &lt;span class="na"&gt;versions&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;v1alpha1&lt;/span&gt;
      &lt;span class="na"&gt;served&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;    &lt;span class="c1"&gt;# this version is active and served by the API Server&lt;/span&gt;
      &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;   &lt;span class="c1"&gt;# this version is used for storage in etcd (only one allowed)&lt;/span&gt;

  &lt;span class="c1"&gt;# Namespaced: resource belongs to a specific namespace&lt;/span&gt;
  &lt;span class="c1"&gt;# Cluster: resource is cluster-wide (like Node, PersistentVolume)&lt;/span&gt;
  &lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespaced&lt;/span&gt;

  &lt;span class="na"&gt;names&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;plural&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;canaries&lt;/span&gt;   &lt;span class="c1"&gt;# kubectl get canaries&lt;/span&gt;
    &lt;span class="na"&gt;singular&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;canary&lt;/span&gt;     &lt;span class="c1"&gt;# kubectl get canary&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;Canary&lt;/span&gt;     &lt;span class="c1"&gt;# used in YAML: kind: Canary&lt;/span&gt;
    &lt;span class="na"&gt;shortNames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;can&lt;/span&gt;               &lt;span class="c1"&gt;# kubectl get can&lt;/span&gt;

  &lt;span class="na"&gt;subresources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;            &lt;span class="c1"&gt;# enables /status subresource (separate update endpoint)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key fields explained
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────────┐
│  metadata.name = "canaries.canarycontroller.tech.com"            │
│                   ────────  ──────────────────────               │
│                   plural    group                                 │
│                   name      name                                  │
└──────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│  REST API path after registration:                               │
│  /apis/canarycontroller.tech.com/v1alpha1/namespaces/{ns}/canaries│
│         ──────────────────────── ────────                        │
│         group                    version                         │
└──────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│  subresources.status: {}                                         │
│  → enables separate /status endpoint                             │
│  → controller updates status via PATCH /status                   │
│  → user updates spec via PATCH /spec                             │
│  → prevents spec/status update conflicts                         │
└──────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Register the CRD with the cluster
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Apply the CRD definition&lt;/span&gt;
kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; crd-canary.yaml

&lt;span class="c"&gt;# Verify it's registered&lt;/span&gt;
kubectl get crd canaries.canarycontroller.tech.com

&lt;span class="c"&gt;# The new resource type is now available&lt;/span&gt;
kubectl get canaries &lt;span class="nt"&gt;--all-namespaces&lt;/span&gt;
kubectl get can &lt;span class="nt"&gt;-n&lt;/span&gt; tech-prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. A Custom Resource Instance
&lt;/h2&gt;

&lt;p&gt;Once the CRD is registered, you can create instances of it — just like built-in resources:&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;canarycontroller.tech.com/v1alpha1&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;Canary&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;go-hello-canary&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tech-prod&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;go-hello&lt;/span&gt;
    &lt;span class="na"&gt;tech.com/clusterId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prod&lt;/span&gt;
  &lt;span class="c1"&gt;# Auto-populated by API Server:&lt;/span&gt;
  &lt;span class="c1"&gt;# resourceVersion: "430698608"&lt;/span&gt;
  &lt;span class="c1"&gt;# uid: c5bb13a2-b2be-11ea-8fef-e4434b7c7170&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;info&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CanaryDeploy&lt;/span&gt;
    &lt;span class="na"&gt;totalBatches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2"&lt;/span&gt;       &lt;span class="c1"&gt;# deploy in 2 batches&lt;/span&gt;
    &lt;span class="na"&gt;currentBatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2"&lt;/span&gt;
    &lt;span class="na"&gt;pauseType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;First&lt;/span&gt;        &lt;span class="c1"&gt;# pause after first batch — wait for human approval&lt;/span&gt;
    &lt;span class="na"&gt;newDeploymentYaml&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;    &lt;span class="c1"&gt;# full YAML of the new version deployment&lt;/span&gt;
      &lt;span class="s"&gt;...&lt;/span&gt;
    &lt;span class="na"&gt;oldDeploymentYaml&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;    &lt;span class="c1"&gt;# full YAML of the current version deployment&lt;/span&gt;
      &lt;span class="s"&gt;...&lt;/span&gt;

&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;availableReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4"&lt;/span&gt;
    &lt;span class="na"&gt;batch2Status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Finished&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What this describes:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go-hello application canary release strategy:
┌─────────────────────────────────────────────────────────┐
│  Total instances: 4                                     │
│  Release strategy: 2 batches                            │
│  Batch 1: deploy 2 new instances → PAUSE                │
│           (wait for human approval via kubectl patch)   │
│  Batch 2: deploy remaining 2 instances → DONE           │
└─────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Go Type Definitions for the CRD
&lt;/h2&gt;

&lt;p&gt;To build a controller for this CRD, you need to define the corresponding Go types. These are what &lt;code&gt;code-generator&lt;/code&gt; will use to generate the typed client, informer, and lister code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Directory structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pkg/
└── apis/
    └── canarycontroller/
        ├── register.go          ← group name constant
        └── v1alpha1/
            ├── doc.go           ← code-gen annotations
            ├── types.go         ← CRD Go type definitions  ← main file
            └── register.go      ← register types with scheme
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  register.go — group name
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// pkg/apis/canarycontroller/register.go&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;canarycontroller&lt;/span&gt;

&lt;span class="k"&gt;const&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="s"&gt;"canarycontroller.tech.com"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  doc.go — code generation annotations
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// pkg/apis/canarycontroller/v1alpha1/doc.go&lt;/span&gt;

&lt;span class="c"&gt;// +k8s:deepcopy-gen=package&lt;/span&gt;
&lt;span class="c"&gt;// +groupName=canarycontroller.tech.com&lt;/span&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;v1alpha1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  types.go — the core type definitions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// pkg/apis/canarycontroller/v1alpha1/types.go&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;v1alpha1&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;metav1&lt;/span&gt; &lt;span class="s"&gt;"k8s.io/apimachinery/pkg/apis/meta/v1"&lt;/span&gt;

&lt;span class="c"&gt;// +genclient&lt;/span&gt;
&lt;span class="c"&gt;// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object&lt;/span&gt;

&lt;span class="c"&gt;// Canary is the Schema for the canaries API&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Canary&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TypeMeta&lt;/span&gt;   &lt;span class="s"&gt;`json:",inline"`&lt;/span&gt;
    &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ObjectMeta&lt;/span&gt; &lt;span class="s"&gt;`json:"metadata,omitempty"`&lt;/span&gt;

    &lt;span class="n"&gt;Spec&lt;/span&gt;   &lt;span class="n"&gt;CanarySpec&lt;/span&gt;   &lt;span class="s"&gt;`json:"spec,omitempty"`&lt;/span&gt;
    &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="n"&gt;CanaryStatus&lt;/span&gt; &lt;span class="s"&gt;`json:"status,omitempty"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// CanarySpec defines the desired state of a Canary release&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;CanarySpec&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Info&lt;/span&gt; &lt;span class="n"&gt;CanaryInfo&lt;/span&gt; &lt;span class="s"&gt;`json:"info"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;CanaryInfo&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// "CanaryDeploy" or "ABTest"&lt;/span&gt;
    &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"type"`&lt;/span&gt;

    &lt;span class="c"&gt;// Total number of batches to roll out&lt;/span&gt;
    &lt;span class="n"&gt;TotalBatches&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"totalBatches"`&lt;/span&gt;

    &lt;span class="c"&gt;// Current batch being processed&lt;/span&gt;
    &lt;span class="n"&gt;CurrentBatch&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"currentBatch"`&lt;/span&gt;

    &lt;span class="c"&gt;// "First": pause after first batch and wait for approval&lt;/span&gt;
    &lt;span class="c"&gt;// "None": roll out all batches automatically&lt;/span&gt;
    &lt;span class="n"&gt;PauseType&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"pauseType"`&lt;/span&gt;

    &lt;span class="c"&gt;// Full YAML of the new version Deployment&lt;/span&gt;
    &lt;span class="n"&gt;NewDeploymentYaml&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"newDeploymentYaml"`&lt;/span&gt;

    &lt;span class="c"&gt;// Full YAML of the current version Deployment&lt;/span&gt;
    &lt;span class="n"&gt;OldDeploymentYaml&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"oldDeploymentYaml"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// CanaryStatus defines the observed state (written by the controller)&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;CanaryStatus&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Info&lt;/span&gt; &lt;span class="n"&gt;CanaryStatusInfo&lt;/span&gt; &lt;span class="s"&gt;`json:"info,omitempty"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;CanaryStatusInfo&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;AvailableReplicas&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"availableReplicas,omitempty"`&lt;/span&gt;
    &lt;span class="n"&gt;Batch1Status&lt;/span&gt;      &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"batch1Status,omitempty"`&lt;/span&gt;
    &lt;span class="n"&gt;Batch2Status&lt;/span&gt;      &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"batch2Status,omitempty"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object&lt;/span&gt;

&lt;span class="c"&gt;// CanaryList is required by the API machinery for List operations&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;CanaryList&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TypeMeta&lt;/span&gt; &lt;span class="s"&gt;`json:",inline"`&lt;/span&gt;
    &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListMeta&lt;/span&gt; &lt;span class="s"&gt;`json:"metadata"`&lt;/span&gt;
    &lt;span class="n"&gt;Items&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Canary&lt;/span&gt;  &lt;span class="s"&gt;`json:"items"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Code generation annotations explained
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Annotation&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;// +genclient&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generate a typed client (&lt;code&gt;CanaryInterface&lt;/code&gt;) for this type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;// +k8s:deepcopy-gen:interfaces=...&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generate &lt;code&gt;DeepCopyObject()&lt;/code&gt; — required by &lt;code&gt;runtime.Object&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;// +k8s:deepcopy-gen=package&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generate &lt;code&gt;DeepCopy()&lt;/code&gt; for all types in this package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;// +groupName=...&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set the API group for generated code&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  5. Spec vs Status: The Controller Contract
&lt;/h2&gt;

&lt;p&gt;The separation of &lt;code&gt;spec&lt;/code&gt; and &lt;code&gt;status&lt;/code&gt; is a fundamental Kubernetes design pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│  spec   — desired state                                     │
│  Written by: the user (kubectl apply)                       │
│  Read by:    the controller                                 │
│                                                             │
│  status — observed state                                    │
│  Written by: the controller (via /status subresource)       │
│  Read by:    the user (kubectl get/describe)                │
└─────────────────────────────────────────────────────────────┘

Controller reconciliation loop:
┌──────────────────────────────────────────────────────────────┐
│                                                              │
│  Read spec  →  compare with status  →  take action          │
│                                              │               │
│                                              ▼               │
│                                       update status          │
│                                       (reflect new reality)  │
└──────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enabling &lt;code&gt;subresources.status: {}&lt;/code&gt; in the CRD YAML is critical — it creates a separate &lt;code&gt;/status&lt;/code&gt; API endpoint, which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users updating &lt;code&gt;spec&lt;/code&gt; won't accidentally overwrite &lt;code&gt;status&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Controllers updating &lt;code&gt;status&lt;/code&gt; won't accidentally overwrite &lt;code&gt;spec&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;RBAC can grant different permissions for spec vs status updates&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. The CRD Lifecycle
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 1: Define the CRD schema (YAML)
        kubectl create -f crd-canary.yaml
        → API Server registers new resource type
        → REST endpoint /apis/canarycontroller.tech.com/v1alpha1/... becomes available

Step 2: Define Go types (types.go)
        → mirrors the CRD schema in Go structs

Step 3: Run code-generator
        → generates typed client (Clientset)
        → generates typed Informer + Lister
        → generates DeepCopy methods

Step 4: Create resource instances
        kubectl apply -f canary-go-hello.yaml
        → Canary object stored in etcd

Step 5: Controller watches and reconciles
        → Informer watches Canary resources
        → Controller reads spec, takes action, updates status
        → Desired state converges to actual state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Detail&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CRD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Registers a new resource type with the API Server — no code required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Custom Resource&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An instance of a CRD — stored in etcd, managed via kubectl&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;spec&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Desired state — written by users, read by controllers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;status&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Observed state — written by controllers, read by users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;subresources.status&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Separates spec/status update paths — prevents conflicts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;scope&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Namespaced&lt;/code&gt; or &lt;code&gt;Cluster&lt;/code&gt; — determines resource visibility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;group/version&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Forms the REST API path: &lt;code&gt;/apis/{group}/{version}/...&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;code-generator&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Generates typed client, Informer, Lister, and DeepCopy from Go types&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;CRD is the "schema" half of the Operator pattern. It extends the Kubernetes API with your domain-specific resource types — giving you the same declarative, watch-driven, etcd-backed machinery that built-in resources enjoy. The controller (Operator) is what brings those resources to life.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next in this series: Operator in Practice: Building a Canary Release Controller (Part 9 — Final)&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Follow the series for more deep dives into Kubernetes development.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;📦 Source Code: &lt;a href="https://github.com/muzinan123/operator" rel="noopener noreferrer"&gt;github.com/muzinan123/operator&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>go</category>
      <category>kubernetes</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>client-go Deep Dive: Controller — The Central Hub That Wires the Informer Framework Together</title>
      <dc:creator>James Lee</dc:creator>
      <pubDate>Tue, 19 May 2026 10:09:48 +0000</pubDate>
      <link>https://forem.com/jamesli/client-go-deep-dive-controller-the-central-hub-that-wires-the-informer-framework-together-1p1d</link>
      <guid>https://forem.com/jamesli/client-go-deep-dive-controller-the-central-hub-that-wires-the-informer-framework-together-1p1d</guid>
      <description>&lt;p&gt;Over the past six articles we've examined each component of the Informer framework individually. Now it's time to look at the component that &lt;strong&gt;wires them all together&lt;/strong&gt;: the Informer-internal &lt;strong&gt;Controller&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Naming clarification:&lt;/strong&gt; The "Controller" in this article is &lt;code&gt;k8s.io/client-go/tools/cache/controller.go&lt;/code&gt; — the &lt;strong&gt;Informer-internal orchestrator&lt;/strong&gt;. It is NOT the same as the business-logic controller you write to reconcile custom resources. We'll call it the &lt;strong&gt;Informer Controller&lt;/strong&gt; throughout this article to avoid confusion.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Source: &lt;code&gt;k8s.io/client-go/tools/cache/controller.go&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Two Types of "Controller" in Kubernetes
&lt;/h2&gt;

&lt;p&gt;Before diving in, let's be precise about terminology:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────────┐
│  Type A: Informer Controller (this article)                      │
│  Package: k8s.io/client-go/tools/cache                          │
│  Role: internal orchestrator — starts Reflector, drives          │
│        processLoop, connects DeltaFIFO → Indexer + callbacks     │
│  You never instantiate this directly.                            │
└──────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│  Type B: Your Application Controller                             │
│  Package: your codebase                                          │
│  Role: business logic — reconciles desired vs actual state       │
│        using WorkQueue + Lister + Clientset                      │
│  You write and own this.                                         │
└──────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. The Controller Struct
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// k8s.io/client-go/tools/cache/controller.go&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;         &lt;span class="n"&gt;Config&lt;/span&gt;          &lt;span class="c"&gt;// all dependencies injected here&lt;/span&gt;
    &lt;span class="n"&gt;reflector&lt;/span&gt;      &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Reflector&lt;/span&gt;      &lt;span class="c"&gt;// created from config at startup&lt;/span&gt;
    &lt;span class="n"&gt;reflectorMutex&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RWMutex&lt;/span&gt;
    &lt;span class="n"&gt;clock&lt;/span&gt;          &lt;span class="n"&gt;clock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Clock&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The controller itself is intentionally thin — all meaningful configuration lives in &lt;code&gt;Config&lt;/code&gt;:&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;type&lt;/span&gt; &lt;span class="n"&gt;Config&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// DeltaFIFO — the event queue (producer: Reflector, consumer: processLoop)&lt;/span&gt;
    &lt;span class="n"&gt;Queue&lt;/span&gt;

    &lt;span class="c"&gt;// Provides List() and Watch() — injected into Reflector at startup&lt;/span&gt;
    &lt;span class="n"&gt;ListerWatcher&lt;/span&gt;

    &lt;span class="c"&gt;// The callback invoked by processLoop for each item popped from DeltaFIFO&lt;/span&gt;
    &lt;span class="c"&gt;// In practice: sharedIndexInformer.HandleDeltas&lt;/span&gt;
    &lt;span class="n"&gt;Process&lt;/span&gt; &lt;span class="n"&gt;ProcessFunc&lt;/span&gt;

    &lt;span class="c"&gt;// The resource type being watched (e.g. *v1.Pod)&lt;/span&gt;
    &lt;span class="n"&gt;ObjectType&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;

    &lt;span class="c"&gt;// How often to force a full resync (0 = never)&lt;/span&gt;
    &lt;span class="n"&gt;FullResyncPeriod&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;Duration&lt;/span&gt;

    &lt;span class="c"&gt;// Optional: custom function to decide whether to resync on each tick&lt;/span&gt;
    &lt;span class="n"&gt;ShouldResync&lt;/span&gt; &lt;span class="n"&gt;ShouldResyncFunc&lt;/span&gt;

    &lt;span class="c"&gt;// If true: when Process() returns an error, re-enqueue the item&lt;/span&gt;
    &lt;span class="n"&gt;RetryOnError&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;

    &lt;span class="c"&gt;// Called when Watch() returns an error&lt;/span&gt;
    &lt;span class="n"&gt;WatchErrorHandler&lt;/span&gt; &lt;span class="n"&gt;WatchErrorHandler&lt;/span&gt;

    &lt;span class="c"&gt;// Pagination size for Watch requests&lt;/span&gt;
    &lt;span class="n"&gt;WatchListPageSize&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Config field map
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Provided by&lt;/th&gt;
&lt;th&gt;Used for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Queue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;DeltaFIFO&lt;/td&gt;
&lt;td&gt;Event buffer between Reflector and processLoop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ListerWatcher&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pod/Deployment Informer's ListFunc+WatchFunc&lt;/td&gt;
&lt;td&gt;Injected into Reflector&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Process&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sharedIndexInformer.HandleDeltas&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Callback for each popped event batch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ObjectType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;e.g. &lt;code&gt;&amp;amp;v1.Pod{}&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Tells Reflector what type to deserialize&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FullResyncPeriod&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;User config (e.g. &lt;code&gt;30*time.Minute&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Periodic forced re-List&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RetryOnError&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Usually &lt;code&gt;false&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Re-enqueue on Process() failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;WatchErrorHandler&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Optional custom handler&lt;/td&gt;
&lt;td&gt;React to Watch connection errors&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  3. How the Informer Controller Starts: Run()
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&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;utilruntime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleCrash&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="c"&gt;// ① Create Reflector from Config&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;NewReflector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListerWatcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ObjectType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c"&gt;// DeltaFIFO is passed as the Store&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FullResyncPeriod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&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;ShouldResync&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ShouldResync&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;WatchListPageSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WatchListPageSize&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;clock&lt;/span&gt;          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clock&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WatchErrorHandler&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;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;watchErrorHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WatchErrorHandler&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reflectorMutex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reflector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reflectorMutex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Group&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// ② Start Reflector in a goroutine — runs List/Watch forever&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartWithChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="p"&gt;,&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;Run&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// ③ Start processLoop — consumes DeltaFIFO forever&lt;/span&gt;
    &lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Until&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processLoop&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;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stopCh&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;Startup sequence:&lt;/strong&gt;&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;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="err"&gt;①&lt;/span&gt; &lt;span class="n"&gt;NewReflector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ListerWatcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ObjectType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DeltaFIFO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resyncPeriod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;         &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;Reflector&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;wired&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;DeltaFIFO&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;its&lt;/span&gt; &lt;span class="n"&gt;Store&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="err"&gt;②&lt;/span&gt; &lt;span class="k"&gt;go&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;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;         &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;Reflector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListAndWatch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;starts&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;background&lt;/span&gt; &lt;span class="n"&gt;goroutine&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;         &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;Phase&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;syncWith&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;DeltaFIFO&lt;/span&gt; &lt;span class="n"&gt;seeded&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;         &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;Phase&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;Watch&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;watchHandler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;into&lt;/span&gt; &lt;span class="n"&gt;DeltaFIFO&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="err"&gt;③&lt;/span&gt; &lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Until&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processLoop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;processLoop&lt;/span&gt; &lt;span class="n"&gt;runs&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;foreground&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;restarted&lt;/span&gt; &lt;span class="n"&gt;every&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;exits&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. The processLoop: Consuming DeltaFIFO
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;processLoop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Pop() blocks until DeltaFIFO has an item&lt;/span&gt;
        &lt;span class="c"&gt;// Passes each item to c.config.Process (= HandleDeltas)&lt;/span&gt;
        &lt;span class="n"&gt;obj&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PopProcessFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Process&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="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="n"&gt;ErrFIFOClosed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;  &lt;span class="c"&gt;// queue was shut down — exit cleanly&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RetryOnError&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c"&gt;// Re-enqueue the item if RetryOnError is set&lt;/span&gt;
                &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddIfNotPresent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&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;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;processLoop flow:&lt;/strong&gt;&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;processLoop&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;runs&lt;/span&gt; &lt;span class="n"&gt;forever&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;DeltaFIFO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HandleDeltas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="err"&gt;│&lt;/span&gt;
           &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;blocks&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&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;queue&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt;
           &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;dequeues&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FIFO&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;calls&lt;/span&gt; &lt;span class="n"&gt;HandleDeltas&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="n"&gt;Delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                      &lt;span class="err"&gt;│&lt;/span&gt;
                      &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Indexer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Delete&lt;/span&gt;   &lt;span class="err"&gt;←&lt;/span&gt; &lt;span class="n"&gt;keep&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;
                      &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;sharedProcessor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;distribute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="err"&gt;←&lt;/span&gt; &lt;span class="n"&gt;fan&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;callbacks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. The Complete Informer Framework — All Components Together
&lt;/h2&gt;

&lt;p&gt;Now that we've covered every component, here is the complete picture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────────────────┐
│                    Informer Framework (full picture)                     │
│                                                                          │
│  ┌──────────────────────────────────────────────────────────────────┐    │
│  │                    sharedIndexInformer                           │    │
│  │                                                                  │    │
│  │  ┌─────────────────────────────────────────────────────────┐    │    │
│  │  │              Informer Controller (internal)             │    │    │
│  │  │                                                         │    │    │
│  │  │   API Server                                            │    │    │
│  │  │       │  List/Watch (HTTP chunked)                      │    │    │
│  │  │       ▼                                                 │    │    │
│  │  │  ┌──────────┐  events   ┌──────────────┐               │    │    │
│  │  │  │ Reflector│ ────────► │  DeltaFIFO   │               │    │    │
│  │  │  │(goroutine│           │  queue+items │               │    │    │
│  │  │  └──────────┘           └──────┬───────┘               │    │    │
│  │  │                                │ Pop()                  │    │    │
│  │  │                                ▼                        │    │    │
│  │  │                        processLoop()                    │    │    │
│  │  │                                │                        │    │    │
│  │  └────────────────────────────────┼────────────────────────┘    │    │
│  │                                   │ HandleDeltas                 │    │
│  │                    ┌──────────────┴──────────────┐              │    │
│  │                    ▼                             ▼              │    │
│  │             ┌────────────┐            ┌──────────────────┐      │    │
│  │             │  Indexer   │            │ sharedProcessor  │      │    │
│  │             │(ThreadSafe │            │  distribute()    │      │    │
│  │             │   Map)     │            └────────┬─────────┘      │    │
│  │             └────────────┘                     │                │    │
│  │                    ▲                           ▼                │    │
│  │                    │ Lister             AddEventHandler         │    │
│  └────────────────────┼───────────────────────────┼───────────────┘    │
│                       │                           │                     │
│              ┌────────┴──────────────────────────▼──────────────┐      │
│              │              Your Application Controller          │      │
│              │                                                   │      │
│              │  podsLister.Pods(ns).Get(name)  ← read from cache │      │
│              │  clientset.CoreV1().Pods().Update() ← write to API│      │
│              │  workqueue.AddRateLimited(key)   ← retry on error │      │
│              │  recorder.Eventf(obj, ...)       ← emit events    │      │
│              └───────────────────────────────────────────────────┘      │
└──────────────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Data Flow: End to End
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="err"&gt;①&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;registered&lt;/span&gt; &lt;span class="n"&gt;informer&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
         &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;sharedIndexInformer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;Reflector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;goroutine&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;processLoop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;              &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;goroutine&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="err"&gt;②&lt;/span&gt; &lt;span class="n"&gt;Goroutine&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;Reflector&lt;/span&gt;
   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;ListAndWatch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
         &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Phase&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;syncWith&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;DeltaFIFO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
         &lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;existing&lt;/span&gt; &lt;span class="n"&gt;objects&lt;/span&gt; &lt;span class="n"&gt;enqueued&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="s"&gt;"Added"&lt;/span&gt; &lt;span class="n"&gt;or&lt;/span&gt; &lt;span class="s"&gt;"Replaced"&lt;/span&gt;
         &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;Phase&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;Watch&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;watchHandler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;DeltaFIFO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Delete&lt;/span&gt;
               &lt;span class="n"&gt;incremental&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;continuously&lt;/span&gt;

&lt;span class="err"&gt;③&lt;/span&gt; &lt;span class="n"&gt;Goroutine&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;processLoop&lt;/span&gt;
   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;DeltaFIFO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HandleDeltas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;blocks&lt;/span&gt; &lt;span class="n"&gt;when&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
         &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;HandleDeltas&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="n"&gt;Delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;Delta&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
               &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Indexer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Delete&lt;/span&gt;   &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="n"&gt;updated&lt;/span&gt;
               &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;sharedProcessor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;distribute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                     &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AddEventHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                           &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;OnAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newObj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                           &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;OnUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldObj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newObj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                           &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;OnDelete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldObj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                 &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;workqueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="err"&gt;④&lt;/span&gt; &lt;span class="n"&gt;Your&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="n"&gt;goroutine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;workqueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;reconcile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;lister&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;              &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;Indexer&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;API&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;clientset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Patch&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Delete&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;write&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;API&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;
               &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;recorder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Eventf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;emit&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;etcd&lt;/span&gt;
               &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;workqueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddRateLimited&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. WaitForCacheSync: Why It Matters
&lt;/h2&gt;

&lt;p&gt;Before your controller starts processing, the local cache must be fully populated from the initial List. &lt;code&gt;WaitForCacheSync&lt;/code&gt; blocks until this is complete:&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;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kc&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;KubeController&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Start all informers&lt;/span&gt;
    &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Block until initial List is complete and DeltaFIFO is drained&lt;/span&gt;
    &lt;span class="c"&gt;// HasSynced() returns true when initialPopulationCount reaches 0&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;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitForCacheSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;podsSynced&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deploymentsSynced&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;span class="n"&gt;utilruntime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleError&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;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"timed out waiting for caches to sync"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Safe to start workers now — Indexer has a complete snapshot&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Until&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runWorker&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;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;stopCh&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;What &lt;code&gt;HasSynced()&lt;/code&gt; tracks internally:&lt;/strong&gt;&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;DeltaFIFO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;initialPopulationCount&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="n"&gt;during&lt;/span&gt; &lt;span class="n"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;decremented&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;Pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
     &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;HasSynced&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt; &lt;span class="n"&gt;when&lt;/span&gt; &lt;span class="n"&gt;initialPopulationCount&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
                        &lt;span class="n"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;least&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;been&lt;/span&gt; &lt;span class="n"&gt;called&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Never start reconciliation workers before &lt;code&gt;WaitForCacheSync&lt;/code&gt; returns.&lt;/strong&gt; If you do, your Lister queries will return incomplete results and your controller will make incorrect decisions based on a partial view of cluster state.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  8. Series Summary: The Complete Component Map
&lt;/h2&gt;

&lt;p&gt;We've now covered every component in the Informer framework. Here's the complete reference:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Article&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reflector&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tools/cache&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List/Watch against API Server; feeds DeltaFIFO&lt;/td&gt;
&lt;td&gt;Part 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DeltaFIFO&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tools/cache&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;FIFO event queue; stores &lt;code&gt;{type, object}&lt;/code&gt; deltas&lt;/td&gt;
&lt;td&gt;Part 3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Indexer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tools/cache&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Thread-safe in-memory cache with custom indexing&lt;/td&gt;
&lt;td&gt;Part 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WorkQueue&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;util/workqueue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rate-limited, deduplicated task queue for workers&lt;/td&gt;
&lt;td&gt;Part 5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EventBroadcaster&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tools/record&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Emits structured Events to API Server / logs&lt;/td&gt;
&lt;td&gt;Part 6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Controller&lt;/strong&gt; (internal)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tools/cache&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Orchestrates Reflector + DeltaFIFO + processLoop&lt;/td&gt;
&lt;td&gt;Part 7 (this)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;sharedProcessor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tools/cache&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fan-out: delivers events to all AddEventHandler listeners&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SharedInformerFactory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;informers&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ensures one Reflector per resource type across all controllers&lt;/td&gt;
&lt;td&gt;Part 1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  9. Summary
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;Informer&lt;/span&gt; &lt;span class="n"&gt;Controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orchestrator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;business&lt;/span&gt; &lt;span class="n"&gt;logic&lt;/span&gt;

&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;NewReflector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ListerWatcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ObjectType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DeltaFIFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;         &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;wires&lt;/span&gt; &lt;span class="n"&gt;API&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;Reflector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;         &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Watch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;forever&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;processLoop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;Pop&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;DeltaFIFO&lt;/span&gt;
               &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;HandleDeltas&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                     &lt;span class="n"&gt;Indexer&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sharedProcessor&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;callbacks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Detail&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;controller struct&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Thin wrapper — holds Config + Reflector reference&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Config.Queue&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;DeltaFIFO — the handoff point between Reflector and processLoop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Config.Process&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;HandleDeltas&lt;/code&gt; — routes events to Indexer and sharedProcessor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Config.RetryOnError&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Re-enqueues items when HandleDeltas returns an error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;processLoop&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Infinite loop: Pop → HandleDeltas → repeat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WaitForCacheSync&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Safety gate — ensures Indexer is fully populated before workers start&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Informer Controller is the invisible backbone of every Kubernetes controller. By orchestrating Reflector, DeltaFIFO, Indexer, and sharedProcessor into a single coherent pipeline, it gives you a reliable, consistent, and efficient view of cluster state — so your application controller can focus entirely on reconciliation logic.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next in this series: CRD: Extending the Kubernetes API with Custom Resources (Part 8)&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Follow the series for more deep dives into Kubernetes development.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;📦 Source Code: &lt;a href="https://github.com/muzinan123/operator" rel="noopener noreferrer"&gt;github.com/muzinan123/operator&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>go</category>
      <category>kubernetes</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>client-go Deep Dive: EventBroadcaster — How Kubernetes Records and Distributes Cluster Events</title>
      <dc:creator>James Lee</dc:creator>
      <pubDate>Tue, 19 May 2026 10:09:20 +0000</pubDate>
      <link>https://forem.com/jamesli/client-go-deep-dive-eventbroadcaster-how-kubernetes-records-and-distributes-cluster-events-582m</link>
      <guid>https://forem.com/jamesli/client-go-deep-dive-eventbroadcaster-how-kubernetes-records-and-distributes-cluster-events-582m</guid>
      <description>&lt;p&gt;In the previous article we covered WorkQueue — the retry and rate-limiting backbone of controllers. In this article we look at a different but equally important mechanism: &lt;strong&gt;EventBroadcaster&lt;/strong&gt;. It's how Kubernetes components record what they're doing, and how you can do the same in your own controllers.&lt;/p&gt;

&lt;p&gt;Source: &lt;code&gt;k8s.io/client-go/tools/record/&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. What Is a Kubernetes Event?
&lt;/h2&gt;

&lt;p&gt;A Kubernetes &lt;strong&gt;Event&lt;/strong&gt; is a first-class resource object — stored in etcd, queryable via kubectl, and subject to the same API machinery as Pods or Deployments.&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;# View recent events in a namespace&lt;/span&gt;
kubectl get events &lt;span class="nt"&gt;-n&lt;/span&gt; default

&lt;span class="c"&gt;# View events for a specific Pod (shown in describe output)&lt;/span&gt;
kubectl describe pod nginx-deployment-7d8ff89d87-25kb4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;LAST SEEN   TYPE      REASON      OBJECT                          MESSAGE
2m          Normal    Scheduled   pod/nginx-7d8ff89d87-25kb4      Successfully assigned default/nginx to node-1
2m          Normal    Pulling     pod/nginx-7d8ff89d87-25kb4      Pulling image "nginx:1.21"
1m          Normal    Pulled      pod/nginx-7d8ff89d87-25kb4      Successfully pulled image in 3.2s
1m          Normal    Created     pod/nginx-7d8ff89d87-25kb4      Created container nginx
1m          Normal    Started     pod/nginx-7d8ff89d87-25kb4      Started container nginx
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Important distinction:&lt;/strong&gt; Kubernetes Events are &lt;strong&gt;resource objects managed by the API Server&lt;/strong&gt;. They are NOT the same as the etcd watch callback events used internally by Informer/Reflector. Don't confuse the two.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. The Event Resource Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// k8s.io/api/core/v1/types.go&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TypeMeta&lt;/span&gt;
    &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ObjectMeta&lt;/span&gt;

    &lt;span class="c"&gt;// The object this event is about (e.g. the Pod that was scheduled)&lt;/span&gt;
    &lt;span class="n"&gt;InvolvedObject&lt;/span&gt; &lt;span class="n"&gt;ObjectReference&lt;/span&gt;

    &lt;span class="c"&gt;// Short machine-readable reason string (e.g. "Scheduled", "Pulling", "Failed")&lt;/span&gt;
    &lt;span class="n"&gt;Reason&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;

    &lt;span class="c"&gt;// Human-readable description of what happened&lt;/span&gt;
    &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;

    &lt;span class="c"&gt;// Component that generated this event&lt;/span&gt;
    &lt;span class="n"&gt;Source&lt;/span&gt; &lt;span class="n"&gt;EventSource&lt;/span&gt;   &lt;span class="c"&gt;// {Component: "scheduler", Host: "master-1"}&lt;/span&gt;

    &lt;span class="c"&gt;// Timing&lt;/span&gt;
    &lt;span class="n"&gt;FirstTimestamp&lt;/span&gt; &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt;      &lt;span class="c"&gt;// when this event first occurred&lt;/span&gt;
    &lt;span class="n"&gt;LastTimestamp&lt;/span&gt;  &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt;      &lt;span class="c"&gt;// most recent occurrence&lt;/span&gt;
    &lt;span class="n"&gt;Count&lt;/span&gt;          &lt;span class="kt"&gt;int32&lt;/span&gt;            &lt;span class="c"&gt;// how many times this event has occurred&lt;/span&gt;

    &lt;span class="c"&gt;// "Normal" or "Warning"&lt;/span&gt;
    &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;

    &lt;span class="c"&gt;// High-precision timestamp (for newer event API)&lt;/span&gt;
    &lt;span class="n"&gt;EventTime&lt;/span&gt; &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MicroTime&lt;/span&gt;

    &lt;span class="c"&gt;// For aggregated/series events&lt;/span&gt;
    &lt;span class="n"&gt;Series&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;EventSeries&lt;/span&gt;

    &lt;span class="c"&gt;// What action was taken&lt;/span&gt;
    &lt;span class="n"&gt;Action&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;

    &lt;span class="c"&gt;// Secondary object involved (e.g. the Node a Pod was scheduled to)&lt;/span&gt;
    &lt;span class="n"&gt;Related&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ObjectReference&lt;/span&gt;

    &lt;span class="c"&gt;// For audit: which controller generated this event&lt;/span&gt;
    &lt;span class="n"&gt;ReportingController&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;ReportingInstance&lt;/span&gt;   &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key fields explained
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Example value&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;InvolvedObject&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{Kind:"Pod", Name:"nginx-xxx"}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The resource this event describes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Reason&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;"Scheduled"&lt;/code&gt;, &lt;code&gt;"Pulling"&lt;/code&gt;, &lt;code&gt;"BackOff"&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Machine-readable event category&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Message&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"Successfully assigned to node-1"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Human-readable detail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;"Normal"&lt;/code&gt; or &lt;code&gt;"Warning"&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Severity indicator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Count&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deduplication counter — same event aggregated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;FirstTimestamp&lt;/code&gt; / &lt;code&gt;LastTimestamp&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;timestamps&lt;/td&gt;
&lt;td&gt;When it first/last occurred&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Source.Component&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;"kubelet"&lt;/code&gt;, &lt;code&gt;"scheduler"&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Which Kubernetes component fired it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  3. Event Retention Policy
&lt;/h2&gt;

&lt;p&gt;Since Events are stored in etcd, unchecked growth would fill disk space. Kubernetes enforces a strict retention policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────┐
│               Event Retention Rules                     │
│                                                         │
│  • Default TTL: 1 hour after last occurrence            │
│  • kubectl get events shows only last-hour events       │
│  • Identical events are AGGREGATED (Count++ instead     │
│    of creating duplicate objects)                       │
│  • etcd stores events in a separate keyspace to         │
│    prevent them from crowding out other resources       │
└─────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is why &lt;code&gt;kubectl describe pod&lt;/code&gt; shows "Events: " for Pods that have been running stably for more than an hour — the events existed, but have been garbage collected.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The EventBroadcaster Pipeline
&lt;/h2&gt;

&lt;p&gt;EventBroadcaster is the mechanism that takes an event generated by a component and delivers it to one or more sinks (e.g. the API Server, a log file, stdout).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────────┐
│                  EventBroadcaster Pipeline                       │
│                                                                  │
│  Your Controller                                                 │
│       │                                                          │
│       │  recorder.Eventf(obj, type, reason, message)             │
│       ▼                                                          │
│  ┌──────────────┐                                                │
│  │EventRecorder │  generates Event object                        │
│  └──────┬───────┘                                                │
│         │                                                        │
│         ▼                                                        │
│  ┌──────────────────┐                                            │
│  │ EventBroadcaster │  fan-out to multiple sinks                 │
│  └──────┬───────────┘                                            │
│         │                                                        │
│    ┌────┴──────────────────────────┐                             │
│    ▼                               ▼                             │
│  ┌──────────────────┐   ┌──────────────────────────┐            │
│  │  API Server Sink │   │  Logging Sink             │            │
│  │  (writes Event   │   │  (prints to stdout/log)   │            │
│  │   to etcd)       │   │                           │            │
│  └──────────────────┘   └──────────────────────────┘            │
└──────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The three actors
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Actor&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EventRecorder&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The interface your code calls — &lt;code&gt;Event()&lt;/code&gt;, &lt;code&gt;Eventf()&lt;/code&gt;, &lt;code&gt;AnnotatedEventf()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EventBroadcaster&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Receives events from recorders, fans out to registered sinks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EventSink&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The destination — API Server (etcd), log output, or custom handler&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  5. Using EventBroadcaster in a Custom Controller
&lt;/h2&gt;

&lt;p&gt;Here's the complete setup pattern used in real Kubernetes controllers:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 — Create the broadcaster and recorder
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"k8s.io/client-go/tools/record"&lt;/span&gt;
    &lt;span class="s"&gt;"k8s.io/client-go/kubernetes/scheme"&lt;/span&gt;
    &lt;span class="n"&gt;corev1&lt;/span&gt; &lt;span class="s"&gt;"k8s.io/api/core/v1"&lt;/span&gt;
    &lt;span class="s"&gt;"k8s.io/apimachinery/pkg/runtime"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientset&lt;/span&gt; &lt;span class="n"&gt;kubernetes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Interface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Create the broadcaster&lt;/span&gt;
    &lt;span class="n"&gt;eventBroadcaster&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewBroadcaster&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Sink 1: write events to the API Server (persisted in etcd)&lt;/span&gt;
    &lt;span class="n"&gt;eventBroadcaster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartRecordingToSink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;typedcorev1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventSinkImpl&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Interface&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;clientset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CoreV1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Events&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c"&gt;// Sink 2: also log events to stdout (useful for debugging)&lt;/span&gt;
    &lt;span class="n"&gt;eventBroadcaster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartEventWatcher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;corev1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;klog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Infof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Event: %s %s %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reason&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c"&gt;// Create a recorder scoped to this controller&lt;/span&gt;
    &lt;span class="c"&gt;// "my-canary-controller" will appear in Event.Source.Component&lt;/span&gt;
    &lt;span class="n"&gt;recorder&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;eventBroadcaster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRecorder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;scheme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;corev1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventSource&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Component&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"my-canary-controller"&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;recorder&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;recorder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="o"&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;h3&gt;
  
  
  Step 2 — Emit events during reconciliation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;reconcile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SplitMetaNamespaceKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Fetch the resource from local cache&lt;/span&gt;
    &lt;span class="n"&gt;canary&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;canaryLister&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Canaries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// --- Normal event: record a successful action ---&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recorder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;canary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c"&gt;// InvolvedObject&lt;/span&gt;
        &lt;span class="n"&gt;corev1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventTypeNormal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"TrafficShifted"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c"&gt;// Reason&lt;/span&gt;
        &lt;span class="s"&gt;"Shifted 10% traffic to canary deployment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// --- Warning event: record a problem ---&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;canary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorRate&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recorder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Eventf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;canary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;corev1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventTypeWarning&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"HighErrorRate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"Canary error rate %.2f%% exceeds threshold %.2f%%, rolling back"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;canary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorRate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;threshold&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rollback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canary&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="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What the emitted Event looks like in kubectl
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;LAST SEEN   TYPE      REASON           OBJECT                  MESSAGE
30s         Normal    TrafficShifted   canary/my-app-canary    Shifted 10% traffic to canary deployment
10s         Warning   HighErrorRate    canary/my-app-canary    Canary error rate 5.23% exceeds threshold 1.00%, rolling back
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Pod Lifecycle Events: The Most Important Events in Practice
&lt;/h2&gt;

&lt;p&gt;Since Kubernetes is Pod-centric — Deployments, StatefulSets, DaemonSets, CronJobs all ultimately create Pods — Pod events are the most frequently used events in production operations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod lifecycle → key events:

┌─────────────────────────────────────────────────────────────────┐
│  Phase          │ Reason           │ Type    │ Source           │
├─────────────────┼──────────────────┼─────────┼──────────────────┤
│  Scheduling     │ Scheduled        │ Normal  │ scheduler        │
│                 │ FailedScheduling │ Warning │ scheduler        │
├─────────────────┼──────────────────┼─────────┼──────────────────┤
│  Image pull     │ Pulling          │ Normal  │ kubelet          │
│                 │ Pulled           │ Normal  │ kubelet          │
│                 │ Failed           │ Warning │ kubelet          │
│                 │ ErrImagePull     │ Warning │ kubelet          │
├─────────────────┼──────────────────┼─────────┼──────────────────┤
│  Container      │ Created          │ Normal  │ kubelet          │
│  lifecycle      │ Started          │ Normal  │ kubelet          │
│                 │ Killing          │ Normal  │ kubelet          │
│                 │ BackOff          │ Warning │ kubelet          │
├─────────────────┼──────────────────┼─────────┼──────────────────┤
│  Node           │ Evicted          │ Warning │ kubelet          │
│                 │ OOMKilling       │ Warning │ kernel/kubelet   │
└─────────────────┴──────────────────┴─────────┴──────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Practical use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Slow startup diagnosis:&lt;/strong&gt; Compare &lt;code&gt;Pulling&lt;/code&gt; → &lt;code&gt;Pulled&lt;/code&gt; timestamps to measure image pull time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crash analysis:&lt;/strong&gt; &lt;code&gt;BackOff&lt;/code&gt; events with increasing intervals signal &lt;code&gt;CrashLoopBackOff&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduling failures:&lt;/strong&gt; &lt;code&gt;FailedScheduling&lt;/code&gt; with reason message explains why a Pod is &lt;code&gt;Pending&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eviction tracking:&lt;/strong&gt; &lt;code&gt;Evicted&lt;/code&gt; events identify nodes under memory pressure&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  7. Summary
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;EventBroadcaster&lt;/span&gt; &lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;

&lt;span class="n"&gt;recorder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Eventf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;▼&lt;/span&gt;
&lt;span class="n"&gt;EventBroadcaster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ActionOrDrop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;StartRecordingToSink&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;clientset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CoreV1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Events&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Patch&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;                             &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aggregates&lt;/span&gt; &lt;span class="n"&gt;duplicate&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="n"&gt;via&lt;/span&gt; &lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;StartEventWatcher&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;    &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;custom&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alerting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Detail&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Event&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A core API resource — stored in etcd, queryable via kubectl&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Type&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Normal&lt;/code&gt; (informational) or &lt;code&gt;Warning&lt;/code&gt; (something needs attention)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reason&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Short machine-readable string — used for filtering and alerting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Count&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Identical events are aggregated — prevents etcd flooding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Retention&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Events are deleted 1 hour after last occurrence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EventRecorder&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Your controller's interface for emitting events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EventBroadcaster&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fan-out hub — delivers events to all registered sinks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EventSink&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Destination: API Server (etcd), stdout log, or custom handler&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;EventBroadcaster closes the observability loop for Kubernetes controllers. By emitting structured events at key decision points in your reconciliation logic, you give operators the same visibility into your custom controller that they have for built-in Kubernetes components — making your controller production-ready and debuggable.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next in this series: Controller: The Central Hub of the Informer Framework (Part 7)&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Follow the series for more deep dives into Kubernetes development.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;📦 Source Code: &lt;a href="https://github.com/muzinan123/operator" rel="noopener noreferrer"&gt;github.com/muzinan123/operator&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>go</category>
      <category>kubernetes</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>client-go Deep Dive: WorkQueue — The Reliable Task Queue for Kubernetes Controllers</title>
      <dc:creator>James Lee</dc:creator>
      <pubDate>Tue, 19 May 2026 10:08:43 +0000</pubDate>
      <link>https://forem.com/jamesli/client-go-deep-dive-workqueue-the-reliable-task-queue-for-kubernetes-controllers-3pjc</link>
      <guid>https://forem.com/jamesli/client-go-deep-dive-workqueue-the-reliable-task-queue-for-kubernetes-controllers-3pjc</guid>
      <description>&lt;p&gt;In the previous article we saw how Indexer stores and indexes resource objects for fast local queries. Now we look at the other half of the controller pattern: &lt;strong&gt;WorkQueue&lt;/strong&gt; — the component that bridges event callbacks and controller reconciliation workers.&lt;/p&gt;

&lt;p&gt;Source: &lt;code&gt;k8s.io/client-go/util/workqueue/&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Where WorkQueue Fits
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;informer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddEventHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ResourceEventHandlerFuncs&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;AddFunc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;UpdateFunc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;DeleteFunc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&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;span class="err"&gt;│&lt;/span&gt;
      &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="n"&gt;fires&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;enqueued&lt;/span&gt;
      &lt;span class="err"&gt;▼&lt;/span&gt;
&lt;span class="err"&gt;┌─────────────────────────────────────────────────┐&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                  &lt;span class="n"&gt;WorkQueue&lt;/span&gt;                      &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;deduplicates&lt;/span&gt; &lt;span class="n"&gt;keys&lt;/span&gt;                            &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt; &lt;span class="n"&gt;limits&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;enqueues&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;             &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;supports&lt;/span&gt; &lt;span class="n"&gt;multiple&lt;/span&gt; &lt;span class="n"&gt;concurrent&lt;/span&gt; &lt;span class="n"&gt;workers&lt;/span&gt;         &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;└─────────────────────────────────────────────────┘&lt;/span&gt;
      &lt;span class="err"&gt;│&lt;/span&gt;
      &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="n"&gt;goroutine&lt;/span&gt; &lt;span class="n"&gt;calls&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="err"&gt;▼&lt;/span&gt;
&lt;span class="n"&gt;Controller&lt;/span&gt; &lt;span class="n"&gt;reconciliation&lt;/span&gt; &lt;span class="n"&gt;logic&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;   &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddRateLimited&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="err"&gt;←&lt;/span&gt; &lt;span class="n"&gt;retry&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;backoff&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key pattern:&lt;/strong&gt; Event handlers only enqueue the &lt;strong&gt;key&lt;/strong&gt; (e.g. &lt;code&gt;"default/nginx"&lt;/code&gt;), never the full object. The worker fetches the latest object from Indexer at processing time — ensuring it always works with the most current state.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. WorkQueue vs Plain FIFO
&lt;/h2&gt;

&lt;p&gt;WorkQueue is not a simple queue. It adds critical properties that make it production-safe for controller development:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Plain FIFO&lt;/th&gt;
&lt;th&gt;WorkQueue&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ordered (FIFO)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Concurrent producers &amp;amp; consumers&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deduplication&lt;/strong&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;&lt;strong&gt;Rate limiting on retry&lt;/strong&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;&lt;strong&gt;Prometheus metrics&lt;/strong&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 (SIGTERM)&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;h3&gt;
  
  
  Deduplication in detail
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Event burst: Pod "nginx" Updated 5 times in 100ms

Plain FIFO:   [nginx, nginx, nginx, nginx, nginx]  ← processed 5 times
WorkQueue:    [nginx]                               ← processed once  ✅

Rule: if a key is already in the queue (not yet processed),
      subsequent Add() calls for the same key are silently dropped.
      The key is only re-eligible after Done() is called.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Three Queue Types
&lt;/h2&gt;

&lt;p&gt;client-go ships three queue implementations, each building on the previous:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────┐
│  Type 1: FIFO Queue                                     │
│  k8s.io/client-go/util/workqueue/queue.go               │
│  Basic ordered queue with deduplication                 │
└─────────────────────────────┬───────────────────────────┘
                              │ extends
┌─────────────────────────────▼───────────────────────────┐
│  Type 2: Delaying Queue                                 │
│  k8s.io/client-go/util/workqueue/delaying_queue.go      │
│  Adds: AddAfter(item, duration) — insert after a delay  │
└─────────────────────────────┬───────────────────────────┘
                              │ extends
┌─────────────────────────────▼───────────────────────────┐
│  Type 3: RateLimiting Queue  ← used in custom controllers│
│  k8s.io/client-go/util/workqueue/rate_limiting_queue.go  │
│  Adds: AddRateLimited, Forget, NumRequeues               │
│  Uses a RateLimiter to compute delay before re-insert    │
└─────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In practice, &lt;strong&gt;custom controllers always use the RateLimiting Queue&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The RateLimiting Queue Interface
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// The rate limiter: decides HOW LONG to delay a re-enqueue&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;RateLimiter&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;When&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;interface&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;Duration&lt;/span&gt;  &lt;span class="c"&gt;// return delay for this item&lt;/span&gt;
    &lt;span class="n"&gt;Forget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;              &lt;span class="c"&gt;// reset the item's failure history&lt;/span&gt;
    &lt;span class="n"&gt;NumRequeues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;     &lt;span class="c"&gt;// how many times has this item failed&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// The queue interface: wraps DelayingInterface + rate limiting methods&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;RateLimitingInterface&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;DelayingInterface&lt;/span&gt;                     &lt;span class="c"&gt;// inherits Add, Get, Done, Len, etc.&lt;/span&gt;
    &lt;span class="n"&gt;AddRateLimited&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;      &lt;span class="c"&gt;// enqueue with rate-limited delay&lt;/span&gt;
    &lt;span class="n"&gt;Forget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;              &lt;span class="c"&gt;// clear failure history for this item&lt;/span&gt;
    &lt;span class="n"&gt;NumRequeues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;     &lt;span class="c"&gt;// query failure count&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Typical controller worker pattern
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;runWorker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processNextItem&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;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;processNextItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Block until an item is available&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quit&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&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;quit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c"&gt;// MUST call Done() when finished&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reconcile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&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="c"&gt;// Success: clear the failure history&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Forget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NumRequeues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;maxRetries&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Transient error: re-enqueue with rate-limited delay&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddRateLimited&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Too many retries: give up and clear history&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Forget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;utilruntime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleError&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="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Three Rate-Limiting Algorithms
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Algorithm 1: Exponential Backoff (ItemExponentialFailureRateLimiter)
&lt;/h3&gt;

&lt;p&gt;When the same item fails repeatedly, the delay grows &lt;strong&gt;exponentially&lt;/strong&gt; with each failure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Failure count → delay:
1st failure:  base delay × 2^0  =  5ms
2nd failure:  base delay × 2^1  = 10ms
3rd failure:  base delay × 2^2  = 20ms
4th failure:  base delay × 2^3  = 40ms
...
nth failure:  min(base × 2^(n-1), maxDelay)   ← capped at maxDelay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Default values used in most controllers&lt;/span&gt;
&lt;span class="n"&gt;workqueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewItemExponentialFailureRateLimiter&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;Millisecond&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c"&gt;// base delay&lt;/span&gt;
    &lt;span class="m"&gt;1000&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;// max delay cap&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;Rate-limiting period:&lt;/strong&gt; starts at &lt;code&gt;AddRateLimited()&lt;/code&gt;, ends at &lt;code&gt;Forget()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Timeline:
t=0ms    AddRateLimited("nginx")  → delay 5ms  → enqueued at t=5ms
t=5ms    Get("nginx") → reconcile → fails
t=5ms    AddRateLimited("nginx")  → delay 10ms → enqueued at t=15ms
t=15ms   Get("nginx") → reconcile → fails
t=15ms   AddRateLimited("nginx")  → delay 20ms → enqueued at t=35ms
...
t=Xms    Get("nginx") → reconcile → SUCCESS
         Forget("nginx")          → failure count reset to 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Real-world example:&lt;/strong&gt; Kubernetes Pod restart policy &lt;code&gt;Always&lt;/code&gt; uses exponential backoff — that's why a crash-looping Pod shows increasing restart intervals (the familiar &lt;code&gt;CrashLoopBackOff&lt;/code&gt; state).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Algorithm 2: Token Bucket (BucketRateLimiter)
&lt;/h3&gt;

&lt;p&gt;The token bucket algorithm controls the &lt;strong&gt;overall throughput&lt;/strong&gt; of the queue, regardless of which specific items are being enqueued.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────┐
│                    Token Bucket                         │
│                                                         │
│  ┌──┬──┬──┬──┬──┐                                       │
│  │🪙│🪙│🪙│🪙│🪙│  ← bucket (fixed capacity)            │
│  └──┴──┴──┴──┴──┘                                       │
│        ▲                    ▲                           │
│  tokens refilled        bucket full:                    │
│  at fixed rate r/s      stop refilling                  │
│                                                         │
│  Each AddRateLimited() consumes one token               │
│  No token available → item must wait                    │
└─────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Uses golang.org/x/time/rate under the hood&lt;/span&gt;
&lt;span class="n"&gt;workqueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewMaxOfRateLimiter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;workqueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewItemExponentialFailureRateLimiter&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;Millisecond&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1000&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;workqueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BucketRateLimiter&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Limiter&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewLimiter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="c"&gt;// 10 tokens/second refill rate, bucket capacity 100&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;How it works:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tokens are added to the bucket at a fixed rate (e.g. 10/sec)&lt;/li&gt;
&lt;li&gt;Bucket has a maximum capacity — once full, new tokens are discarded&lt;/li&gt;
&lt;li&gt;Each &lt;code&gt;AddRateLimited()&lt;/code&gt; call requires one token&lt;/li&gt;
&lt;li&gt;If no token is available, the item is delayed until a token is refilled&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Used in:&lt;/strong&gt; Nginx rate limiting, Envoy Ratelimit, Sentinel — token bucket is one of the most widely adopted rate-limiting algorithms in distributed systems.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Algorithm 3: Counter with Fast/Slow Lanes (ItemFastSlowRateLimiter)
&lt;/h3&gt;

&lt;p&gt;The counter algorithm limits how many items can be enqueued within a time window. WorkQueue extends the basic counter with &lt;strong&gt;two insertion rates&lt;/strong&gt;: a fast lane and a slow lane.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Configuration:
  fastDelay       = 5ms      ← interval between items in fast lane
  slowDelay       = 1000ms   ← interval between items in slow lane
  maxFastAttempts = 3        ← how many failures use fast lane before switching

Failure timeline for one item:
┌──────────────────────────────────────────────────────────┐
│  Attempt 1 → delay 5ms    (fast lane, attempt 1/3)       │
│  Attempt 2 → delay 5ms    (fast lane, attempt 2/3)       │
│  Attempt 3 → delay 5ms    (fast lane, attempt 3/3)       │
│  Attempt 4 → delay 1000ms (slow lane — maxFastAttempts   │
│                             exceeded)                    │
│  Attempt 5 → delay 1000ms (slow lane)                    │
│  ...                                                     │
└──────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;workqueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewItemFastSlowRateLimiter&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;Millisecond&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c"&gt;// fastDelay&lt;/span&gt;
    &lt;span class="m"&gt;1000&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;Millisecond&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="c"&gt;// slowDelay&lt;/span&gt;
    &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                    &lt;span class="c"&gt;// maxFastAttempts&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;Use case:&lt;/strong&gt; Suitable for scenarios where a few quick retries are acceptable (transient network blips), but sustained failures should back off aggressively to avoid resource exhaustion.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Choosing a Rate Limiter
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Algorithm&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Exponential Backoff&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Per-item retry (most common)&lt;/td&gt;
&lt;td&gt;Delay doubles with each failure; resets on success&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Token Bucket&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Global throughput cap&lt;/td&gt;
&lt;td&gt;Smooth rate limit across all items; burst-friendly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fast/Slow Counter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tiered retry strategy&lt;/td&gt;
&lt;td&gt;Quick retries first, then aggressive backoff&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In practice, the &lt;strong&gt;default rate limiter&lt;/strong&gt; used by &lt;code&gt;controller-runtime&lt;/code&gt; and most Kubernetes controllers combines exponential backoff and token bucket via &lt;code&gt;NewMaxOfRateLimiter&lt;/code&gt; — taking the &lt;strong&gt;maximum delay&lt;/strong&gt; from both algorithms:&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;// Default: use whichever algorithm gives the LONGER delay&lt;/span&gt;
&lt;span class="c"&gt;// This ensures both per-item backoff AND global rate cap are respected&lt;/span&gt;
&lt;span class="n"&gt;workqueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultControllerRateLimiter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c"&gt;// = NewMaxOfRateLimiter(&lt;/span&gt;
&lt;span class="c"&gt;//     NewItemExponentialFailureRateLimiter(5ms, 1000s),&lt;/span&gt;
&lt;span class="c"&gt;//     &amp;amp;BucketRateLimiter{rate.NewLimiter(rate.Limit(10), 100)},&lt;/span&gt;
&lt;span class="c"&gt;//   )&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Summary
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WorkQueue lifecycle in a controller:

Event fires (Add/Update/Delete)
     │
     ▼
queue.Add(key)          ← deduplicated: same key added once
     │
     ▼
worker: queue.Get(key)  ← blocks until item available
     │
     ├── reconcile OK  → queue.Forget(key) + queue.Done(key)
     │
     └── reconcile ERR → queue.AddRateLimited(key)
                            │
                            └── RateLimiter.When(key) → delay
                                AddAfter(key, delay)  → DelayingQueue
                                → re-enters queue after delay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FIFO Queue&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Base: ordered, deduplicated, concurrent-safe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Delaying Queue&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Adds &lt;code&gt;AddAfter(item, duration)&lt;/code&gt; for time-delayed insertion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RateLimiting Queue&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Adds &lt;code&gt;AddRateLimited&lt;/code&gt; — computes delay via RateLimiter before calling AddAfter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Exponential Backoff&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Per-item delay that doubles on each failure — prevents hammering a broken resource&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Token Bucket&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Global throughput cap — prevents queue from overwhelming the API Server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fast/Slow Counter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tiered retry — fast initial retries, slow sustained retries&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;WorkQueue is the safety net of every Kubernetes controller. Its combination of deduplication, rate limiting, and retry semantics ensures that controllers converge to desired state reliably — even under API Server failures, network partitions, or event storms.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next in this series: EventBroadcaster: How Kubernetes Records and Distributes Cluster Events (Part 6)&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Follow the series for more deep dives into Kubernetes development.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;📦 Source Code: &lt;a href="https://github.com/muzinan123/operator" rel="noopener noreferrer"&gt;github.com/muzinan123/operator&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>go</category>
      <category>kubernetes</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>client-go Deep Dive: Indexer — Fast In-Memory Resource Storage with Custom Indexing</title>
      <dc:creator>James Lee</dc:creator>
      <pubDate>Tue, 19 May 2026 10:08:05 +0000</pubDate>
      <link>https://forem.com/jamesli/client-go-deep-dive-indexer-fast-in-memory-resource-storage-with-custom-indexing-37jc</link>
      <guid>https://forem.com/jamesli/client-go-deep-dive-indexer-fast-in-memory-resource-storage-with-custom-indexing-37jc</guid>
      <description>&lt;p&gt;In the previous article we saw that &lt;code&gt;HandleDeltas&lt;/code&gt; routes every event to two destinations — one of them is &lt;strong&gt;Indexer&lt;/strong&gt;. Indexer is the local in-memory cache that makes resource queries fast and keeps the API Server load-free. In this article we'll look at how it's built and how to extend it with custom index functions.&lt;/p&gt;

&lt;p&gt;Source: &lt;code&gt;k8s.io/client-go/tools/cache/index.go&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. What Is Indexer?
&lt;/h2&gt;

&lt;p&gt;Indexer is the &lt;strong&gt;local read cache&lt;/strong&gt; of the Informer framework. Once the initial List completes and the cache is synced, all resource queries go through Indexer — never hitting the API Server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────┐
│                   Indexer                           │
│                                                     │
│  ┌───────────────────────────────────────────────┐  │
│  │              ThreadSafeMap                    │  │
│  │  (concurrent-safe storage backend)            │  │
│  │                                               │  │
│  │  items: map[string]interface{}                │  │
│  │  key = "namespace/name"  value = resource obj │  │
│  └───────────────────────────────────────────────┘  │
│                                                     │
│  ┌───────────────────────────────────────────────┐  │
│  │           Index Layer (on top)                │  │
│  │  Indexers: map[indexName]IndexFunc            │  │
│  │  Indices:  map[indexName]Index                │  │
│  │  Index:    map[indexKey]sets.String           │  │
│  └───────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Indexer has two layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ThreadSafeMap&lt;/strong&gt; — the raw concurrent-safe key/value store&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Index layer&lt;/strong&gt; — pluggable custom index functions for efficient filtered queries&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. ThreadSafeMap: The Storage Backend
&lt;/h2&gt;

&lt;p&gt;Source: &lt;code&gt;k8s.io/client-go/tools/cache/thread_safe_store.go&lt;/code&gt;&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;type&lt;/span&gt; &lt;span class="n"&gt;threadSafeMap&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt;     &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RWMutex&lt;/span&gt;          &lt;span class="c"&gt;// read-write lock for concurrent safety&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt;    &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c"&gt;// primary storage: key → resource object&lt;/span&gt;
    &lt;span class="n"&gt;indexers&lt;/span&gt; &lt;span class="n"&gt;Indexers&lt;/span&gt;               &lt;span class="c"&gt;// registered index functions&lt;/span&gt;
    &lt;span class="n"&gt;indices&lt;/span&gt;  &lt;span class="n"&gt;Indices&lt;/span&gt;                &lt;span class="c"&gt;// computed index data&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key format
&lt;/h3&gt;

&lt;p&gt;The default key function is &lt;code&gt;MetaNamespaceKeyFunc&lt;/code&gt;, which produces keys in the format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;namespace/name    →  "default/nginx-pod"
cluster-scoped    →  "my-node"   (no namespace prefix)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CRUD operations
&lt;/h3&gt;

&lt;p&gt;ThreadSafeMap exposes standard storage operations, all protected by &lt;code&gt;sync.RWMutex&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Lock type&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Add(key, obj)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write&lt;/td&gt;
&lt;td&gt;Insert object + update all index entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Update(key, obj)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write&lt;/td&gt;
&lt;td&gt;Replace object + rebuild index entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Delete(key)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write&lt;/td&gt;
&lt;td&gt;Remove object + clean up index entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Get(key)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;Fetch single object by key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;List()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;Return all objects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ListKeys()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;Return all keys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ByIndex(indexName, indexKey)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;Return all objects matching an index query&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write path (Add/Update/Delete):
┌─────────────────────────────────────────────────┐
│  lock.Lock()                                    │
│  ├── modify items map                           │
│  ├── updateIndices() or deleteFromIndices()     │
│  └── lock.Unlock()                              │
└─────────────────────────────────────────────────┘

Read path (Get/List/ByIndex):
┌─────────────────────────────────────────────────┐
│  lock.RLock()   ← multiple readers in parallel  │
│  ├── read from items or indices                 │
│  └── lock.RUnlock()                             │
└─────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. The Four Index Data Structures
&lt;/h2&gt;

&lt;p&gt;Indexer's power comes from its pluggable index system. Four types work together:&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;// A registry of named index functions&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Indexers&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;IndexFunc&lt;/span&gt;

&lt;span class="c"&gt;// An index function: given an object, return the index keys it belongs to&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;IndexFunc&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// A registry of computed index data (one per registered IndexFunc)&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Indices&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;Index&lt;/span&gt;

&lt;span class="c"&gt;// The actual index: maps an index key to the set of object keys that match&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Index&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;sets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How they relate
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Indexers["byNamespace"] = namespaceIndexFunc
Indexers["byLabel"]     = labelIndexFunc
      │
      │  when an object is added/updated, each IndexFunc is called
      ▼
Indices["byNamespace"] = Index{
    "default":     {"default/nginx", "default/redis"},
    "kube-system": {"kube-system/coredns"},
}
Indices["byLabel"] = Index{
    "app=web":   {"default/nginx", "default/frontend"},
    "app=cache": {"default/redis"},
}
      │
      │  query: ByIndex("byLabel", "app=web")
      ▼
returns: [nginx object, frontend object]   ← O(1) lookup via set
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Visual summary
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────┐
│  Indexers (function registry)                                │
│  ┌────────────────┬──────────────────────────────────────┐   │
│  │ "byNamespace"  │ func(obj) → [namespace]              │   │
│  │ "byLabel/foo"  │ func(obj) → [label value of "foo"]   │   │
│  └────────────────┴──────────────────────────────────────┘   │
│                          │ applied on every Add/Update        │
│                          ▼                                    │
│  Indices (computed data)                                      │
│  ┌────────────────┬──────────────────────────────────────┐   │
│  │ "byNamespace"  │ {"default": {"ns/pod1","ns/pod2"}}   │   │
│  │ "byLabel/foo"  │ {"bar": {"ns/pod1"}, "biz":{"ns/pod3"}}  │
│  └────────────────┴──────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Custom Index Functions in Practice
&lt;/h2&gt;

&lt;p&gt;The real power of Indexer is that you can register &lt;strong&gt;any index function&lt;/strong&gt; at initialization time. Here's the complete example from the client-go test suite:&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;// Custom index function: index Pods by the value of their "foo" label&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;testIndexFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pod&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Labels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"foo"&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestGetIndexFuncValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Initialize Indexer with:&lt;/span&gt;
    &lt;span class="c"&gt;//   key function:   MetaNamespaceKeyFunc  → "namespace/name"&lt;/span&gt;
    &lt;span class="c"&gt;//   index function: testIndexFunc         → registered as "testmodes"&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewIndexer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MetaNamespaceKeyFunc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Indexers&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"testmodes"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;testIndexFunc&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;pod1&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pod&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ObjectMeta&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ObjectMeta&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"one"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Labels&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"foo"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;}}}&lt;/span&gt;
    &lt;span class="n"&gt;pod2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pod&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ObjectMeta&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ObjectMeta&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"two"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Labels&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"foo"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;}}}&lt;/span&gt;
    &lt;span class="n"&gt;pod3&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pod&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ObjectMeta&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ObjectMeta&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"tre"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Labels&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"foo"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"biz"&lt;/span&gt;&lt;span class="p"&gt;}}}&lt;/span&gt;

    &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pod1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pod2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pod3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// List all distinct values produced by the "testmodes" index function&lt;/span&gt;
    &lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListIndexFuncValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"testmodes"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// keys = ["bar", "biz"]  — the two distinct label values&lt;/span&gt;

    &lt;span class="c"&gt;// Query all Pods where label "foo" == "bar"&lt;/span&gt;
    &lt;span class="n"&gt;pods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ByIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"testmodes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// pods = [pod1, pod2]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What happens internally when &lt;code&gt;index.Add(pod1)&lt;/code&gt; is called
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pod1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"default/one"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pod1&lt;/span&gt;        &lt;span class="err"&gt;←&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;primary&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;registered&lt;/span&gt; &lt;span class="n"&gt;IndexFunc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
           &lt;span class="n"&gt;testIndexFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pod1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
           &lt;span class="n"&gt;Indices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"testmodes"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"default/one"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;After&lt;/span&gt; &lt;span class="n"&gt;adding&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="n"&gt;pods&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;

&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"default/one"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pod1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"default/two"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pod2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"default/tre"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pod3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;Indices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"testmodes"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"bar"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"default/one"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"default/two"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="s"&gt;"biz"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"default/tre"&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;h3&gt;
  
  
  Query flow: &lt;code&gt;ByIndex("testmodes", "bar")&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ByIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"testmodes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;look&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt; &lt;span class="n"&gt;Indices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"testmodes"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"default/one"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"default/two"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
           &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"default/one"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;pod1&lt;/span&gt;
           &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"default/two"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;pod2&lt;/span&gt;

&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pod1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pod2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="err"&gt;←&lt;/span&gt; &lt;span class="n"&gt;O&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="n"&gt;lookup&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;O&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="n"&gt;fetch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Built-in Index Functions
&lt;/h2&gt;

&lt;p&gt;client-go ships with a standard index function for the most common query 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="c"&gt;// MetaNamespaceIndexFunc — index objects by namespace&lt;/span&gt;
&lt;span class="c"&gt;// This is the default index registered in most Informers&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;MetaNamespaceIndexFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;meta&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;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Accessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&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;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"object has no meta: %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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetNamespace&lt;/span&gt;&lt;span class="p"&gt;()},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&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;// Get all Pods in the "production" namespace — from local cache, no API call&lt;/span&gt;
&lt;span class="n"&gt;pods&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;podsLister&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"production"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Everything&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c"&gt;// Internally this calls:&lt;/span&gt;
&lt;span class="c"&gt;// indexer.ByIndex("namespace", "production")&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Indexer vs Direct API Query
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Indexer (local cache)&lt;/th&gt;
&lt;th&gt;Direct API Server call&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Microseconds (in-memory)&lt;/td&gt;
&lt;td&gt;Milliseconds (network + etcd)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;API Server load&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Zero&lt;/td&gt;
&lt;td&gt;One request per query&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Consistency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Eventually consistent (synced via Watch)&lt;/td&gt;
&lt;td&gt;Strongly consistent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Controller reconciliation loops&lt;/td&gt;
&lt;td&gt;One-time admin queries&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rule of thumb:&lt;/strong&gt; In any controller hot path — reconciliation loops, event handlers, health checks — always use the Lister (backed by Indexer). Only use Clientset for &lt;strong&gt;writes&lt;/strong&gt; (Create/Update/Delete/Patch).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  7. Summary
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Indexer = ThreadSafeMap + pluggable Index functions

┌──────────────────────────────────────────────────────────┐
│  Write path (from HandleDeltas):                         │
│  Add/Update/Delete → update items + rebuild index data   │
│                                                          │
│  Read path (from your controller via Lister):            │
│  Get(key)              → O(1) direct lookup              │
│  List()                → O(n) full scan                  │
│  ByIndex(name, value)  → O(1) index lookup + O(k) fetch  │
└──────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Detail&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ThreadSafeMap&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;sync.RWMutex&lt;/code&gt; + &lt;code&gt;map[string]interface{}&lt;/code&gt; — the raw storage layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MetaNamespaceKeyFunc&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Default key function: produces &lt;code&gt;"namespace/name"&lt;/code&gt; keys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Indexers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Registry of named index functions — define what you can query by&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;IndexFunc&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;User-defined function: &lt;code&gt;obj → []indexKey&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Indices&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Computed index data: &lt;code&gt;indexName → indexKey → set of object keys&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ByIndex&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Efficient filtered query: O(1) index lookup + O(k) object retrieval&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Indexer is what makes Kubernetes controllers fast. By keeping a fully indexed in-memory snapshot of cluster state, it eliminates the need for controllers to poll the API Server — turning what would be thousands of network calls per second into zero-latency local memory reads.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next in this series: WorkQueue: The Reliable Task Queue for Kubernetes Controllers (Part 5)&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Follow the series for more deep dives into Kubernetes development.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;📦 Source Code: &lt;a href="https://github.com/muzinan123/operator" rel="noopener noreferrer"&gt;github.com/muzinan123/operator&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>go</category>
      <category>kubernetes</category>
      <category>performance</category>
    </item>
    <item>
      <title>client-go Deep Dive: DeltaFIFO — The Event Queue Behind Informer</title>
      <dc:creator>James Lee</dc:creator>
      <pubDate>Tue, 19 May 2026 10:07:34 +0000</pubDate>
      <link>https://forem.com/jamesli/client-go-deep-dive-deltafifo-the-event-queue-behind-informer-38l</link>
      <guid>https://forem.com/jamesli/client-go-deep-dive-deltafifo-the-event-queue-behind-informer-38l</guid>
      <description>&lt;p&gt;In the previous article we saw how Reflector calls &lt;code&gt;List/Watch&lt;/code&gt; and feeds events downstream. The immediate destination of those events is &lt;strong&gt;DeltaFIFO&lt;/strong&gt; — the event queue that sits at the heart of the Informer framework.&lt;/p&gt;

&lt;p&gt;Source: &lt;code&gt;k8s.io/client-go/tools/cache/delta_fifo.go&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. What Is DeltaFIFO?
&lt;/h2&gt;

&lt;p&gt;The name has two parts:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FIFO&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;First-In-First-Out queue — supports &lt;code&gt;Add&lt;/code&gt;, &lt;code&gt;Update&lt;/code&gt;, &lt;code&gt;Delete&lt;/code&gt;, &lt;code&gt;List&lt;/code&gt;, &lt;code&gt;Pop&lt;/code&gt; operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Delta&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Each entry stores not just the object, but also the &lt;strong&gt;type of change&lt;/strong&gt; (Added / Updated / Deleted / Sync / Replaced)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Together, DeltaFIFO is a queue where each item carries both &lt;strong&gt;what changed&lt;/strong&gt; and &lt;strong&gt;how it changed&lt;/strong&gt; — giving downstream consumers the full context they need to act correctly.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The Data Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// k8s.io/client-go/tools/cache/delta_fifo.go&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;DeltaFIFO&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RWMutex&lt;/span&gt;
    &lt;span class="n"&gt;cond&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cond&lt;/span&gt;             &lt;span class="c"&gt;// used to block/unblock consumers&lt;/span&gt;

    &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;Deltas&lt;/span&gt;    &lt;span class="c"&gt;// key → list of deltas for that object&lt;/span&gt;
    &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;             &lt;span class="c"&gt;// ordered list of keys (FIFO ordering)&lt;/span&gt;

    &lt;span class="n"&gt;populated&lt;/span&gt;              &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;initialPopulationCount&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;  &lt;span class="c"&gt;// tracks how many items came from the initial List&lt;/span&gt;

    &lt;span class="n"&gt;keyFunc&lt;/span&gt;      &lt;span class="n"&gt;KeyFunc&lt;/span&gt;         &lt;span class="c"&gt;// computes the key for a given object&lt;/span&gt;
    &lt;span class="n"&gt;knownObjects&lt;/span&gt; &lt;span class="n"&gt;KeyListerGetter&lt;/span&gt; &lt;span class="c"&gt;// reference to Indexer (for deletion detection)&lt;/span&gt;

    &lt;span class="n"&gt;closed&lt;/span&gt;                &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;emitDeltaTypeReplaced&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Deltas&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Delta&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Delta&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Type&lt;/span&gt;   &lt;span class="n"&gt;DeltaType&lt;/span&gt;    &lt;span class="c"&gt;// Added | Updated | Deleted | Replaced | Sync&lt;/span&gt;
    &lt;span class="n"&gt;Object&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;  &lt;span class="c"&gt;// the actual Kubernetes resource object&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Three Core Fields
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;queue:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"pod/default/nginx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pod/default/redis"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deploy/default/app"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="err"&gt;↑&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ordered&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;slice&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;keys&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(FIFO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;order)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;items:&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;"pod/default/nginx"&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="err"&gt;Added&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;PodObj_v&lt;/span&gt;&lt;span class="mi"&gt;1&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="err"&gt;Updated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;PodObj_v&lt;/span&gt;&lt;span class="mi"&gt;2&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;"pod/default/redis"&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="err"&gt;Deleted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;PodObj_v&lt;/span&gt;&lt;span class="mi"&gt;1&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;"deploy/default/app"&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="err"&gt;Added&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;DeployObj_v&lt;/span&gt;&lt;span class="mi"&gt;1&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="err"&gt;↑&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;map:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="err"&gt;Delta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pending&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;changes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;that&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;Delta:&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="err"&gt;Type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Updated"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Object:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;Pod&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;nginx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;v&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;&amp;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="err"&gt;↑&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;single&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;change&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;event:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;what&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;happened&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;snapshot&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Visualizing the Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│                        DeltaFIFO                            │
│                                                             │
│  queue (FIFO order):                                        │
│  ┌──────────────────┬──────────────────┬─────────────────┐  │
│  │ "pod/default/    │ "pod/default/    │ "deploy/default │  │
│  │  nginx"          │  redis"          │  /app"          │  │
│  └──────────────────┴──────────────────┴─────────────────┘  │
│          │                   │                  │            │
│          ▼                   ▼                  ▼            │
│  items (map):                                               │
│  ┌──────────────────┐ ┌────────────────┐ ┌──────────────┐  │
│  │ [{Added, nginx}  │ │[{Deleted,      │ │[{Added,      │  │
│  │  {Updated,nginx}]│ │  redis}]       │ │  deploy}]    │  │
│  └──────────────────┘ └────────────────┘ └──────────────┘  │
└─────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key design insight:&lt;/strong&gt; &lt;code&gt;queue&lt;/code&gt; maintains ordering (which object to process next), while &lt;code&gt;items&lt;/code&gt; accumulates all pending deltas per object. Multiple changes to the same object are batched — but never reordered relative to other objects.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3. Producing Messages: queueActionLocked
&lt;/h2&gt;

&lt;p&gt;Every time Reflector calls &lt;code&gt;syncWith()&lt;/code&gt; (from List) or &lt;code&gt;watchHandler()&lt;/code&gt; (from Watch), it ultimately calls &lt;code&gt;queueActionLocked&lt;/code&gt; to enqueue an event:&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;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;DeltaFIFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;queueActionLocked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actionType&lt;/span&gt; &lt;span class="n"&gt;DeltaType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// ① Compute the object's key (e.g. "default/nginx")&lt;/span&gt;
    &lt;span class="n"&gt;id&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;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeyOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;KeyError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;obj&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="c"&gt;// ② Append new Delta to the existing list for this key&lt;/span&gt;
    &lt;span class="n"&gt;oldDeltas&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;newDeltas&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldDeltas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Delta&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;actionType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c"&gt;// ③ Deduplicate consecutive identical events&lt;/span&gt;
    &lt;span class="n"&gt;newDeltas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dedupDeltas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newDeltas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newDeltas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// ④ If this key is new, add it to the queue (maintain FIFO order)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exists&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c"&gt;// ⑤ Update items map with the new delta list&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newDeltas&lt;/span&gt;

        &lt;span class="c"&gt;// ⑥ Wake up all blocked consumers&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Broadcast&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="no"&gt;nil&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;Production flow:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Reflector (r.syncWith / r.watchHandler)
     │
     ▼
queueActionLocked(actionType, obj)
     │
     ├── ① KeyOf(obj)              → compute key (e.g. "default/nginx")
     ├── ② append Delta            → add {type, obj} to existing delta list
     ├── ③ dedupDeltas()           → remove redundant consecutive events
     ├── ④ queue = append(key)     → add key to FIFO queue (if new)
     ├── ⑤ items[key] = newDeltas  → store updated delta list
     └── ⑥ cond.Broadcast()        → wake up Pop() consumers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Delta Types
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Added&lt;/span&gt;    &lt;span class="n"&gt;DeltaType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Added"&lt;/span&gt;     &lt;span class="c"&gt;// object newly appeared (from Watch or initial List)&lt;/span&gt;
    &lt;span class="n"&gt;Updated&lt;/span&gt;  &lt;span class="n"&gt;DeltaType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Updated"&lt;/span&gt;   &lt;span class="c"&gt;// object was modified&lt;/span&gt;
    &lt;span class="n"&gt;Deleted&lt;/span&gt;  &lt;span class="n"&gt;DeltaType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Deleted"&lt;/span&gt;   &lt;span class="c"&gt;// object was removed&lt;/span&gt;
    &lt;span class="n"&gt;Replaced&lt;/span&gt; &lt;span class="n"&gt;DeltaType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Replaced"&lt;/span&gt;  &lt;span class="c"&gt;// full re-list replaced the object (resync)&lt;/span&gt;
    &lt;span class="n"&gt;Sync&lt;/span&gt;     &lt;span class="n"&gt;DeltaType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Sync"&lt;/span&gt;      &lt;span class="c"&gt;// periodic resync — object unchanged but re-delivered&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deduplication: dedupDeltas
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;dedupDeltas&lt;/code&gt; prevents redundant back-to-back &lt;code&gt;Deleted&lt;/code&gt; events for the same object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before dedup:  [{Updated, obj}, {Deleted, obj}, {Deleted, obj}]
After dedup:   [{Updated, obj}, {Deleted, obj}]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only the &lt;strong&gt;last two deltas&lt;/strong&gt; are considered for deduplication — older history is always preserved.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Consuming Messages: Pop
&lt;/h2&gt;

&lt;p&gt;The consumer side is driven by the Informer's internal Controller, which calls &lt;code&gt;Pop()&lt;/code&gt; in its &lt;code&gt;processLoop&lt;/code&gt;:&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;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;DeltaFIFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="n"&gt;PopProcessFunc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&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;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// ① Block if queue is empty — wait for producer to signal&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&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;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;closed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&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;ErrFIFOClosed&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cond&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c"&gt;// releases lock and sleeps until cond.Broadcast()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// ② Dequeue the first key (FIFO order)&lt;/span&gt;
        &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&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;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;initialPopulationCount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;initialPopulationCount&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// ③ Retrieve and remove the delta list for this key&lt;/span&gt;
        &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;id&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;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;  &lt;span class="c"&gt;// key was already processed (race condition guard)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// ④ Pass the delta list to the callback function (HandleDeltas)&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;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// ⑤ If processing failed, re-enqueue for retry&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ErrRequeue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addIfNotPresent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&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;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Err&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;item&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Consumption flow:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Controller.processLoop()
     │
     └── DeltaFIFO.Pop(HandleDeltas)
           │
           ├── ① cond.Wait()       → sleep if queue empty
           ├── ② dequeue key       → take first key from FIFO queue
           ├── ③ delete(items,id)  → remove delta list from map
           ├── ④ process(item)     → call HandleDeltas callback
           └── ⑤ on error:
                 addIfNotPresent() → re-enqueue for retry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. HandleDeltas: Routing Events Downstream
&lt;/h2&gt;

&lt;p&gt;Once &lt;code&gt;Pop()&lt;/code&gt; delivers a delta list to the callback, &lt;code&gt;HandleDeltas&lt;/code&gt; routes each event to &lt;strong&gt;two destinations&lt;/strong&gt;:&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;// k8s.io/client-go/tools/cache/shared_informer.go&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sharedIndexInformer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;HandleDeltas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blockDeltas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&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;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blockDeltas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Deltas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;Sync&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Replaced&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Added&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Updated&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exists&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;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&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="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;exists&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c"&gt;// Object already in cache → Update&lt;/span&gt;
                &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="n"&gt;isSync&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Sync&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Replaced&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;sameResourceVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

                &lt;span class="c"&gt;// Route to ShareInformer listeners&lt;/span&gt;
                &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;distribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;updateNotification&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;oldObj&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newObj&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;isSync&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c"&gt;// Object not in cache → Add&lt;/span&gt;
                &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;distribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addNotification&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;newObj&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;Deleted&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;distribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deleteNotification&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;oldObj&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;false&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Two Destinations
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;HandleDeltas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Deltas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="err"&gt;①&lt;/span&gt; &lt;span class="n"&gt;Indexer&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;Added&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Updated&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Replaced&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Sync&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;indexer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;or&lt;/span&gt; &lt;span class="n"&gt;indexer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;     &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;Deleted&lt;/span&gt;                     &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;indexer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
     &lt;span class="err"&gt;│&lt;/span&gt;
     &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="err"&gt;②&lt;/span&gt; &lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;distribute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ShareInformer&lt;/span&gt; &lt;span class="n"&gt;fan&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;addNotification&lt;/span&gt;    &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;triggers&lt;/span&gt; &lt;span class="n"&gt;OnAdd&lt;/span&gt;  &lt;span class="n"&gt;callbacks&lt;/span&gt;
           &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;updateNotification&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;triggers&lt;/span&gt; &lt;span class="n"&gt;OnUpdate&lt;/span&gt; &lt;span class="n"&gt;callbacks&lt;/span&gt;
           &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;deleteNotification&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;triggers&lt;/span&gt; &lt;span class="n"&gt;OnDelete&lt;/span&gt; &lt;span class="n"&gt;callbacks&lt;/span&gt;
                      &lt;span class="err"&gt;│&lt;/span&gt;
                      &lt;span class="err"&gt;▼&lt;/span&gt;
             &lt;span class="n"&gt;informer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddEventHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ResourceEventHandlerFuncs&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                 &lt;span class="n"&gt;AddFunc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;workqueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                 &lt;span class="n"&gt;UpdateFunc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;workqueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                 &lt;span class="n"&gt;DeleteFunc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;workqueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&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;h2&gt;
  
  
  6. The Complete DeltaFIFO Lifecycle
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────┐
│                     DeltaFIFO Lifecycle                         │
│                                                                 │
│  PRODUCER (Reflector)                                           │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │  r.syncWith()      → queueActionLocked(Added, obj)       │   │
│  │  r.watchHandler()  → queueActionLocked(Updated/Deleted…) │   │
│  └──────────────────────────────────────────────────────────┘   │
│                          │ cond.Broadcast()                     │
│                          ▼                                      │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │                    DeltaFIFO                             │   │
│  │  queue: [key1, key2, key3, ...]   (FIFO order)           │   │
│  │  items: {key1: [Δ,Δ], key2: [Δ], key3: [Δ,Δ,Δ]}        │   │
│  └──────────────────────────────────────────────────────────┘   │
│                          │ cond.Wait → unblock                  │
│                          ▼                                      │
│  CONSUMER (Controller.processLoop)                              │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │  Pop(HandleDeltas)                                       │   │
│  │    → HandleDeltas                                        │   │
│  │        ├── Indexer.Add/Update/Delete  (local cache)      │   │
│  │        └── processor.distribute()    (event callbacks)   │   │
│  └──────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Detail&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;queue&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ordered slice of object keys — guarantees FIFO processing order&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;items&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Map of key → &lt;code&gt;[]Delta&lt;/code&gt; — accumulates all pending changes per object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Delta&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;{Type, Object}&lt;/code&gt; — carries both the change type and the full object snapshot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;queueActionLocked&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Producer entry point — appends delta, deduplicates, signals consumers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;dedupDeltas&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Removes redundant back-to-back Deleted events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pop&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Consumer entry point — blocks when empty, dequeues FIFO, calls HandleDeltas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HandleDeltas&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Routes each delta to Indexer (storage) AND processor.distribute (callbacks)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;cond.Broadcast/Wait&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Efficient producer-consumer synchronization — no busy polling&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;DeltaFIFO is the reliable handoff point between Reflector (producer) and the Informer's internal Controller (consumer). Its dual structure — an ordered queue for sequencing plus a map for delta accumulation — ensures that no event is lost, no object is processed out of order, and downstream consumers always receive the full change context.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next in this series: Indexer: Fast In-Memory Resource Storage with Thread-Safe Indexing (Part 4)&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Follow the series for more deep dives into Kubernetes development.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;📦 Source Code: &lt;a href="https://github.com/muzinan123/operator" rel="noopener noreferrer"&gt;github.com/muzinan123/operator&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>go</category>
      <category>kubernetes</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>client-go Deep Dive: Reflector — How Kubernetes Syncs Resources from the API Server</title>
      <dc:creator>James Lee</dc:creator>
      <pubDate>Tue, 19 May 2026 10:06:09 +0000</pubDate>
      <link>https://forem.com/jamesli/client-go-deep-dive-reflector-how-kubernetes-syncs-resources-from-the-api-server-42l6</link>
      <guid>https://forem.com/jamesli/client-go-deep-dive-reflector-how-kubernetes-syncs-resources-from-the-api-server-42l6</guid>
      <description>&lt;p&gt;In the previous article we saw that Informer's core mechanism is &lt;strong&gt;List/Watch&lt;/strong&gt;. The component responsible for executing that mechanism is &lt;strong&gt;Reflector&lt;/strong&gt;. Every time an Informer starts up, it's Reflector that connects to the API Server, fetches the full resource snapshot, and then keeps watching for changes.&lt;/p&gt;

&lt;p&gt;Source: &lt;code&gt;k8s.io/client-go/tools/cache/reflector.go&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Where Reflector Fits
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Informer starts
     │
     ▼
┌──────────────────────────────────────────────────┐
│                   Reflector                      │
│                                                  │
│  Phase 1: LIST                                   │
│  ├── call listerWatcher.List()                   │
│  ├── get ResourceVersion                         │
│  ├── extract object list                         │
│  └── syncWith() → store all objects in DeltaFIFO │
│                                                  │
│  Phase 2: WATCH                                  │
│  ├── call listerWatcher.Watch()                  │
│  ├── receive incremental events (HTTP chunked)   │
│  └── watchHandler() → push events to DeltaFIFO  │
└──────────────────────────────────────────────────┘
     │
     ▼
DeltaFIFO (event queue)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. The Reflector Struct
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// k8s.io/client-go/tools/cache/reflector.go&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Reflector&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;             &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;expectedTypeName&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;expectedType&lt;/span&gt;     &lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;          &lt;span class="c"&gt;// the resource type being watched (e.g. *v1.Pod)&lt;/span&gt;
    &lt;span class="n"&gt;expectedGVK&lt;/span&gt;      &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GroupVersionKind&lt;/span&gt;

    &lt;span class="n"&gt;store&lt;/span&gt;            &lt;span class="n"&gt;Store&lt;/span&gt;                 &lt;span class="c"&gt;// DeltaFIFO — where events are written&lt;/span&gt;
    &lt;span class="n"&gt;listerWatcher&lt;/span&gt;    &lt;span class="n"&gt;ListerWatcher&lt;/span&gt;         &lt;span class="c"&gt;// the actual List/Watch implementation&lt;/span&gt;

    &lt;span class="n"&gt;backoffManager&lt;/span&gt;         &lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BackoffManager&lt;/span&gt;  &lt;span class="c"&gt;// retry backoff for Watch reconnects&lt;/span&gt;
    &lt;span class="n"&gt;initConnBackoffManager&lt;/span&gt; &lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BackoffManager&lt;/span&gt;  &lt;span class="c"&gt;// backoff for initial connection&lt;/span&gt;

    &lt;span class="n"&gt;resyncPeriod&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;Duration&lt;/span&gt;         &lt;span class="c"&gt;// how often to force a full resync (0 = never)&lt;/span&gt;
    &lt;span class="n"&gt;ShouldResync&lt;/span&gt;     &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;           &lt;span class="c"&gt;// optional: custom resync decision function&lt;/span&gt;

    &lt;span class="n"&gt;clock&lt;/span&gt;            &lt;span class="n"&gt;clock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Clock&lt;/span&gt;
    &lt;span class="n"&gt;paginatedResult&lt;/span&gt;  &lt;span class="kt"&gt;bool&lt;/span&gt;

    &lt;span class="c"&gt;// ResourceVersion tracking — critical for Watch correctness&lt;/span&gt;
    &lt;span class="n"&gt;lastSyncResourceVersion&lt;/span&gt;              &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;isLastSyncResourceVersionUnavailable&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;lastSyncResourceVersionMutex&lt;/span&gt;         &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RWMutex&lt;/span&gt;

    &lt;span class="n"&gt;WatchListPageSize&lt;/span&gt;  &lt;span class="kt"&gt;int64&lt;/span&gt;
    &lt;span class="n"&gt;watchErrorHandler&lt;/span&gt;  &lt;span class="n"&gt;WatchErrorHandler&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;Key fields explained:&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;Field&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;store&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The DeltaFIFO queue — Reflector writes all events here&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;listerWatcher&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Interface that provides the actual &lt;code&gt;List()&lt;/code&gt; and &lt;code&gt;Watch()&lt;/code&gt; calls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lastSyncResourceVersion&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tracks the latest version seen — Watch resumes from this point after reconnect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;resyncPeriod&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;If &amp;gt; 0, Reflector periodically forces a full re-List to catch any missed events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;backoffManager&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exponential backoff when Watch connection drops&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  3. The ListerWatcher Interface
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;listerWatcher&lt;/code&gt; is an interface — Reflector doesn't know or care which resource type it's watching. The concrete implementation is injected per resource type.&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;type&lt;/span&gt; &lt;span class="n"&gt;ListerWatcher&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Lister&lt;/span&gt;
    &lt;span class="n"&gt;Watcher&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Lister&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Watcher&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Interface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&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;For a Pod Informer, the concrete implementation looks 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;// k8s.io/client-go/informers/core/v1/pods.go&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewFilteredPodInformer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="n"&gt;kubernetes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Interface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;resyncPeriod&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;Duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;indexers&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Indexers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tweakListOptions&lt;/span&gt; &lt;span class="n"&gt;internalinterfaces&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TweakListOptionsFunc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SharedIndexInformer&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;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewSharedIndexInformer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListWatch&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c"&gt;// List: calls the real Kubernetes API&lt;/span&gt;
            &lt;span class="n"&gt;ListFunc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&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;tweakListOptions&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;tweakListOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;options&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;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CoreV1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;List&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;TODO&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="c"&gt;// Watch: opens a long-lived HTTP connection to the API Server&lt;/span&gt;
            &lt;span class="n"&gt;WatchFunc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Interface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&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;tweakListOptions&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;tweakListOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;options&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;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CoreV1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Watch&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;TODO&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;options&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;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;corev1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pod&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
        &lt;span class="n"&gt;resyncPeriod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;indexers&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;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This is why Clientset must be created before SharedInformerFactory.&lt;/strong&gt; The &lt;code&gt;ListFunc&lt;/code&gt; and &lt;code&gt;WatchFunc&lt;/code&gt; are closures over the Clientset — without it, Reflector has no way to talk to the API Server.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewKubeController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;KubeController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;kc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;KubeController&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;clientset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;clientset&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Clientset is passed in here — it flows down into every ListFunc/WatchFunc&lt;/span&gt;
    &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;informers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewSharedInformerFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;defaultResync&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;podInformer&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Core&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;V1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pods&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;podsLister&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;podInformer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lister&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;podsSynced&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;podInformer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Informer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasSynced&lt;/span&gt;
    &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deploymentInformer&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Apps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;V1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Deployments&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deploymentsLister&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deploymentInformer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lister&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deploymentsSynced&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deploymentInformer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Informer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasSynced&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;kc&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. ListAndWatch: Phase 1 — Full List
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;ListAndWatch&lt;/code&gt; method is the heart of Reflector. Phase 1 fetches the complete current state:&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;func&lt;/span&gt; &lt;span class="p"&gt;(&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;Reflector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ListAndWatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;resourceVersion&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListOptions&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ResourceVersion&lt;/span&gt;&lt;span class="o"&gt;:&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;relistResourceVersion&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="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// ① Fetch all resources (with pagination support)&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;pager&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;pager&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;pager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SimplePageFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&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;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listerWatcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c"&gt;// → calls ListFunc → Clientset.CoreV1().Pods().List()&lt;/span&gt;
            &lt;span class="p"&gt;}))&lt;/span&gt;
            &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;paginatedResult&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;pager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;List&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="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c"&gt;// handle expired ResourceVersion: retry with fresh version&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isExpiredError&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="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;isTooLargeResourceVersionError&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;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;paginatedResult&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;pager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;List&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="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListOptions&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ResourceVersion&lt;/span&gt;&lt;span class="o"&gt;:&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;relistResourceVersion&lt;/span&gt;&lt;span class="p"&gt;()})&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listCh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}()&lt;/span&gt;

        &lt;span class="c"&gt;// wait for list to complete or stop signal&lt;/span&gt;
        &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;panicCh&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;listCh&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// ② Extract ResourceVersion from the list response&lt;/span&gt;
        &lt;span class="n"&gt;listMetaInterface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListAccessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;resourceVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;listMetaInterface&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetResourceVersion&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c"&gt;// ③ Convert list result into a slice of runtime.Object&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExtractList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// ④ Store all objects + ResourceVersion into DeltaFIFO&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;syncWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resourceVersion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&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;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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// ⑤ Record the latest ResourceVersion — Watch will resume from here&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;setLastSyncResourceVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resourceVersion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&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;Phase 1 call chain:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ListAndWatch()
  │
  ├── ① r.listerWatcher.List()        → fetch all objects from API Server
  ├── ② listMetaInterface.GetResourceVersion()  → extract version stamp
  ├── ③ meta.ExtractList()            → convert to []runtime.Object
  ├── ④ r.syncWith()                  → write all objects into DeltaFIFO
  └── ⑤ r.setLastSyncResourceVersion() → save version for Watch resume point
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. ListAndWatch: Phase 2 — Continuous Watch
&lt;/h2&gt;

&lt;p&gt;After the full List completes, Reflector enters an infinite loop watching for incremental changes:&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;// Periodic resync goroutine (if resyncPeriod &amp;gt; 0)&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;resyncCh&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;if&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;ShouldResync&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;||&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;ShouldResync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&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;store&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Resync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c"&gt;// force re-sync of Indexer from DeltaFIFO&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&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;span class="c"&gt;// Main Watch loop&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;stopCh&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
        &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// Add randomized timeout to prevent thundering herd on reconnect&lt;/span&gt;
        &lt;span class="n"&gt;timeoutSeconds&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minWatchTimeout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Seconds&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Float64&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;metav1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListOptions&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;ResourceVersion&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;resourceVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c"&gt;// resume from last known version&lt;/span&gt;
            &lt;span class="n"&gt;TimeoutSeconds&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;timeoutSeconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;AllowWatchBookmarks&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// ① Open a long-lived Watch connection to the API Server&lt;/span&gt;
        &lt;span class="n"&gt;w&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;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listerWatcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;utilnet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsConnectionRefused&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="o"&gt;&amp;lt;-&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;initConnBackoffManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Backoff&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c"&gt;// backoff and retry&lt;/span&gt;
                &lt;span class="k"&gt;continue&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;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// ② Process incoming events: write to DeltaFIFO + update ResourceVersion&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="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;watchHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;resourceVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resyncerrc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stopCh&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="no"&gt;nil&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;isExpiredError&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="c"&gt;// log unexpected errors&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&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;Phase 2 call chain:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ListAndWatch() — Watch loop
  │
  ├── ① r.listerWatcher.Watch()    → open HTTP long-poll to API Server
  │                                   (passes ResourceVersion to resume from)
  └── ② r.watchHandler()           → for each incoming event:
                                       write object to DeltaFIFO
                                       update lastSyncResourceVersion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. ResourceVersion: The Key to Reliable Watch
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ResourceVersion&lt;/code&gt; is a monotonically increasing version stamp that etcd assigns to every resource object. It's the mechanism that makes Watch reliable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;List response:  ResourceVersion = "1000"
                (all objects as of version 1000)
     │
     ▼
Watch request:  ResourceVersion = "1000"
                (give me all events AFTER version 1000)
     │
     ▼
API Server streams:
  - Pod "nginx" Updated  (RV=1001)
  - Pod "redis" Deleted  (RV=1002)
  - ...

If Watch connection drops:
     │
     ▼
Reflector reconnects with:  ResourceVersion = "1002"
(resumes exactly where it left off — no events missed, no duplicates)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;ResourceVersion behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fresh start&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;""&lt;/code&gt; or &lt;code&gt;"0"&lt;/code&gt; — get latest snapshot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;After List&lt;/td&gt;
&lt;td&gt;Set to the version returned by List response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;After each Watch event&lt;/td&gt;
&lt;td&gt;Updated to the event's ResourceVersion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Watch reconnect&lt;/td&gt;
&lt;td&gt;Resumes from &lt;code&gt;lastSyncResourceVersion&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expired version (too old)&lt;/td&gt;
&lt;td&gt;Triggers a fresh List from scratch&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  7. Under the Hood: How Watch Works (HTTP Chunked Transfer)
&lt;/h2&gt;

&lt;p&gt;The Watch connection is not a WebSocket or gRPC stream — it's a plain &lt;strong&gt;HTTP/1.1 long-lived connection&lt;/strong&gt; using &lt;strong&gt;Chunked Transfer Encoding&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client (Reflector)                    API Server
     │                                     │
     │  GET /api/v1/pods?watch=true        │
     │  ResourceVersion=1000               │
     │ ──────────────────────────────────► │
     │                                     │
     │  HTTP/1.1 200 OK                    │
     │  Transfer-Encoding: chunked         │
     │ ◄────────────────────────────────── │
     │                                     │
     │  chunk: {"type":"ADDED","object":…} │
     │ ◄────────────────────────────────── │
     │                                     │
     │  chunk: {"type":"MODIFIED","object":…}
     │ ◄────────────────────────────────── │
     │                                     │
     │  (connection stays open…)           │
     │  (new chunks arrive as events occur)│
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why Chunked Transfer Encoding?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In standard HTTP, the &lt;code&gt;Content-Length&lt;/code&gt; header tells the client how many bytes to expect. But for a Watch stream, the server doesn't know in advance how many events will occur — the stream is open-ended.&lt;/p&gt;

&lt;p&gt;Chunked Transfer Encoding solves this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The response body is split into &lt;strong&gt;variable-size chunks&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Each chunk is prefixed with its size in hex&lt;/li&gt;
&lt;li&gt;The server sends chunks as events arrive — no pre-declared content length needed&lt;/li&gt;
&lt;li&gt;A zero-length chunk signals the end of the stream
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="ne"&gt;OK&lt;/span&gt;
&lt;span class="na"&gt;Transfer-Encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chunked&lt;/span&gt;

1a\r\n                          ← chunk size (hex)
{"type":"ADDED","object":…}\r\n ← chunk data
\r\n
2f\r\n
{"type":"MODIFIED","object":…}\r\n
\r\n
0\r\n                           ← end of stream
\r\n
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This is only available in &lt;strong&gt;HTTP/1.1&lt;/strong&gt; and later. It's what makes Kubernetes Watch efficient — a single persistent connection replaces thousands of polling requests.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  8. Summary
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Reflector.Run()
     │
     └── ListAndWatch()
           │
           ├── Phase 1: LIST
           │     ├── listerWatcher.List()          → full snapshot from API Server
           │     ├── GetResourceVersion()           → stamp the snapshot version
           │     ├── meta.ExtractList()             → parse into objects
           │     └── syncWith() → DeltaFIFO         → seed the local cache
           │
           └── Phase 2: WATCH (infinite loop)
                 ├── listerWatcher.Watch(RV)        → HTTP chunked long-poll
                 ├── watchHandler() → DeltaFIFO     → stream events to queue
                 └── on disconnect: backoff + retry
                     on expired RV: re-List from scratch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Detail&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ListerWatcher&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Interface injected per resource type; backed by Clientset API calls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ResourceVersion&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;etcd version stamp; enables Watch to resume without missing events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DeltaFIFO&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The downstream queue; Reflector is its sole producer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Chunked Transfer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HTTP/1.1 mechanism that keeps the Watch connection open indefinitely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Backoff&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Exponential retry when Watch connection drops or API Server is unavailable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Reflector is the bridge between the Kubernetes API Server and the local Informer cache. Once you understand its List → syncWith → Watch → watchHandler pipeline, the reliability guarantees of the entire Informer framework become clear.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next in this series: DeltaFIFO: The Event Queue Behind Informer (Part 3)&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Follow the series for more deep dives into Kubernetes development.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;📦 Source Code: &lt;a href="https://github.com/muzinan123/operator" rel="noopener noreferrer"&gt;github.com/muzinan123/operator&lt;/a&gt;&lt;/p&gt;

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