Report
In pkg/psmdb/mongo/mongo.go, the Dial function does a single
mongo.Connect + Ping and returns the error directly:
client, err := mongo.Connect(ctx, opts)
if err != nil {
return nil, errors.Wrap(err, "connect mongo")
}
if err := client.Ping(ctx, readpref.Primary()); err != nil {
return nil, errors.Wrap(err, "ping mongo")
}
return client, nil
There is no retry. Any transient error — EOF on socket close, server
selection timeout, context deadline — bubbles up immediately and fails
the entire reconcile.
More about the problem
The operator logs Dial failures like:
connect mongo: ... EOF
ping mongo: server selection error: server selection timeout
and the reconcile aborts. The operator relies entirely on the next
reconcile to retry, which restarts the whole flow from scratch.
This is particularly painful in service-mesh deployments (Istio/ASM):
after a new mongo pod is created, the client-side proxy may take
seconds-to-minutes to receive the necessary CDS/EDS config from istiod.
During this window the proxy falls back to PassthroughCluster and
sends plain TCP, which the mongo-side proxy (STRICT mTLS) rejects with
filter_chain_not_found — manifesting as EOF on the client.
Combined with the non-idempotent handleReplsetInit (see related
issue #2374), this single transient failure can permanently break a
freshly-deployed cluster: the Dial failure aborts the reconcile right
after createUser consumed the localhost-exception, and the retry can
never finish the bootstrap.
Steps to reproduce
- Kubernetes cluster with cluster-wide STRICT PeerAuthentication
(Istio/ASM)
- Apply a PerconaServerMongoDB CR
- Observe
Dial failing with EOF / "server selection timeout" while
the sidecar of the new mongo pod waits for EDS config
- The operator does not retry within the reconcile; the reconcile
fails, cluster init stays incomplete
Versions
- Operator: 1.22.x (tested);
Dial in pkg/psmdb/mongo/mongo.go is
unchanged in current main
- Kubernetes: GKE with managed ASM (Istio data plane, Traffic Director
control plane), cluster-wide STRICT mTLS
- EDS-sync windows measured in production: up to ~2.5 min
Anything else?
Suggested fix — wrap Connect + Ping in
wait.ExponentialBackoff with a transient-error filter. Only retry on
connection-level errors (EOF, timeout) — NOT on auth errors or other
definitive failures:
import "k8s.io/apimachinery/pkg/util/wait"
var client *mongo.Client
err := wait.ExponentialBackoff(wait.Backoff{
Steps: 10,
Duration: 2 * time.Second,
Factor: 1.5,
Cap: 30 * time.Second,
}, func() (bool, error) {
c, err := mongo.Connect(ctx, opts)
if err != nil {
if isTransientError(err) { return false, nil }
return false, err
}
if pingErr := c.Ping(ctx, readpref.Primary()); pingErr != nil {
c.Disconnect(ctx)
if isTransientError(pingErr) { return false, nil }
return false, pingErr
}
client = c
return true, nil
})
Total retry budget ~5 min with exponential backoff — covers the Istio
EDS-sync windows we've measured in production (up to ~2.5 min).
Report
In
pkg/psmdb/mongo/mongo.go, theDialfunction does a singlemongo.Connect+Pingand returns the error directly:There is no retry. Any transient error — EOF on socket close, server
selection timeout, context deadline — bubbles up immediately and fails
the entire reconcile.
More about the problem
The operator logs
Dialfailures like:and the reconcile aborts. The operator relies entirely on the next
reconcile to retry, which restarts the whole flow from scratch.
This is particularly painful in service-mesh deployments (Istio/ASM):
after a new mongo pod is created, the client-side proxy may take
seconds-to-minutes to receive the necessary CDS/EDS config from istiod.
During this window the proxy falls back to
PassthroughClusterandsends plain TCP, which the mongo-side proxy (STRICT mTLS) rejects with
filter_chain_not_found— manifesting as EOF on the client.Combined with the non-idempotent
handleReplsetInit(see relatedissue #2374), this single transient failure can permanently break a
freshly-deployed cluster: the Dial failure aborts the reconcile right
after
createUserconsumed the localhost-exception, and the retry cannever finish the bootstrap.
Steps to reproduce
(Istio/ASM)
Dialfailing with EOF / "server selection timeout" whilethe sidecar of the new mongo pod waits for EDS config
fails, cluster init stays incomplete
Versions
Dialinpkg/psmdb/mongo/mongo.goisunchanged in current main
control plane), cluster-wide STRICT mTLS
Anything else?
Suggested fix — wrap
Connect+Pinginwait.ExponentialBackoffwith a transient-error filter. Only retry onconnection-level errors (EOF, timeout) — NOT on auth errors or other
definitive failures: