Dennis-Mircea Ciupitu created FLINK-41465:
---------------------------------------------

             Summary: Health probe reports healthy while the informer receives 
no events
                 Key: FLINK-41465
                 URL: https://issues.apache.org/jira/browse/FLINK-41465
             Project: Flink
          Issue Type: Bug
          Components: Kubernetes Operator
            Reporter: Dennis-Mircea Ciupitu


h1. Problem

The operator learns about resources only through the watch connections of its 
informers. The health probe judges an informer by JOSDK's health indicator, 
which comes down to {{isRunning()}} and {{{}hasSynced(){}}}: the informer was 
started and completed its first list. Neither says anything about whether 
events still arrive.

Two failure classes leave an informer silent while the probe keeps answering 
200. The operator then ignores new resources and spec changes until someone 
restarts it. Existing deployments are still reconciled on the timer, so nothing 
else looks wrong.
h2. 1. The watch is alive and delivers nothing

Seen in production on operator 1.16.1: a FlinkDeployment created in a watched 
namespace had no status, no event and no log line for 12 hours. The API server 
returned it on every read and {{kubectl get --watch}} received its events, the 
operator log showed no connection error at all, and the operator's watch 
connections stayed open. This matches a stale watch cache on the API server 
replica the operator's connections were pinned to. A restart fixed it 
instantly, because the fresh informers listed everything.

The same state is reproducible with a TLS proxy between the operator and the 
API server that forwards everything except the server-to-client data frames of 
watch connections (events and bookmarks) while keeping ping, pong and close 
frames. The watches stay connected, the pings are answered, and a 
FlinkDeployment created behind the proxy never gets a status, with the health 
endpoint at 200 on every check. The API server's own watch timeout does not 
help: it closes each watch after ten minutes, fabric8 reopens it and the 
replayed ADD event is lost again. A connection that becomes half-open, when the 
server side disappears without a TCP reset, produces a shorter blind window of 
one to two minutes with the same 200 answers.

A resource created during such a window also depends on the next watch working: 
after a restart the first reconcile only adds the operator finalizer, and the 
actual deployment is triggered by the watch event of that update.
h2. 2. The watch is down and keeps retrying

A watch that fails after startup is retried forever by fabric8: 
{{{}InformerHealthIndicator.{}}}{{{}isRunning(){}}} and 
{{{}InformerHealthIndicator.{}}}{{{}hasSynced(){}}} stay true, so JOSDK reports 
the informer healthy.

This is reproducible by deleting a watched namespace on an operator installed 
with namespace-scoped RBAC: the log shows an endless {{Received 403 on 
websocket}} loop while the probe stays OK. The same holds for an API server 
that becomes unreachable after startup. Only the deprecated JOSDK 
{{InformerHealthIndicator.isWatching()}} would show it, and it is not part of 
JOSDK's health status.
h1. Root cause

The probe evaluates the client's belief about its watch and the completion of 
the initial sync. It never looks at the one thing that proves a watch is alive: 
data arriving. The canary resources do look at it end to end, but only where a 
canary is deployed, only for the FlinkDeployment informer of that namespace, 
and at the cost of their own write traffic.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to