()
| 338 | p.mu.Unlock() |
| 339 | |
| 340 | // Phase 2 (unlocked): perform the slow I/O. Holding p.mu across this is a |
| 341 | // bug — RefreshS3Secret runs a CREATE OR REPLACE SECRET which can block |
| 342 | // indefinitely if the active client query is monopolising a single-conn |
| 343 | // *sql.DB, and any concurrent health check needs p.mu.RLock to snapshot |
| 344 | // sessions for stall detection. Releasing the lock here keeps the gRPC |
| 345 | // health check responsive even when the secret rotation has to wait. |
| 346 | if needsRefresh { |
| 347 | if refreshFn == nil { |
| 348 | refreshFn = server.RefreshS3Secret |
| 349 | } |
| 350 | if payload.DuckLake.ObjectStore != "" { |
| 351 | // The refresh rebuilds the ducklake_s3 secret from this config, so |
| 352 | // it must carry the same cache-proxy transport (HTTPProxy + |
| 353 | // USE_SSL=false + pinned endpoint) the attach path applies — |
| 354 | // otherwise the first CP-driven credential rotation replaces the |
| 355 | // path-style plain-HTTP secret with a vhost/HTTPS one and every S3 |
| 356 | // read CONNECT-tunnels past the NVMe cache for the rest of the |
| 357 | // worker's life (mw-prod-us 2026-07-17). |
| 358 | // |
no test coverage detected