tryFastFailOpen returns the configured fail-open user when ALL of the following hold: 1. Fail-open is enabled in the config (otherwise there's no emergency user to serve, so we must run the real DB path even during outage). 2. The connectorDown latch is set (some prior request observed a transport/
()
| 284 | // signal needed — the caller doesn't need to know whether we fast-pathed |
| 285 | // because fail-open is disabled vs. because the connector is healthy. |
| 286 | func (s *DatabaseStrategy) tryFastFailOpen() *common.User { |
| 287 | u := s.buildFailOpenUser() |
| 288 | if u == nil { |
| 289 | // Fail-open not configured — every request must go through the real |
| 290 | // DB path even during an outage. Keeps the strict-auth semantics. |
| 291 | return nil |
| 292 | } |
| 293 | if !s.connectorDown.Load() { |
| 294 | return nil |
| 295 | } |
| 296 | now := time.Now().UnixNano() |
| 297 | since := s.connectorDownSince.Load() |
| 298 | if now-since > int64(connectorDownProbeInterval) { |
| 299 | // Probe window expired. The caller that wins the CAS gets to run a |
| 300 | // real DB query (which will mark up or mark down again based on the |
| 301 | // result); everyone else continues to fast-path. |
| 302 | if s.connectorDownSince.CompareAndSwap(since, now) { |
| 303 | return nil |
| 304 | } |
| 305 | } |
| 306 | return u |
| 307 | } |
| 308 | |
| 309 | // isDownSignal reports whether a connector error should set the |
| 310 | // connectorDown latch. We're deliberately narrow here: |