acquire returns a connected browser, reusing the live instance when it is still healthy and relaunching otherwise. Honors the failure cooldown.
()
| 201 | // acquire returns a connected browser, reusing the live instance when it |
| 202 | // is still healthy and relaunching otherwise. Honors the failure cooldown. |
| 203 | func (s *renderSession) acquire() (*rod.Browser, error) { |
| 204 | s.mu.Lock() |
| 205 | defer s.mu.Unlock() |
| 206 | |
| 207 | if remaining := time.Until(s.cooldownUntil); remaining > 0 { |
| 208 | return nil, fmt.Errorf("headless rendering suspended after repeated browser failures; retrying in %s", remaining.Round(time.Second)) |
| 209 | } |
| 210 | if s.browser != nil { |
| 211 | if _, err := (proto.BrowserGetVersion{}).Call(s.browser); err == nil { |
| 212 | s.touchLocked() |
| 213 | return s.browser, nil |
| 214 | } |
| 215 | // The browser died underneath us (OOM-killed, crashed): relaunch. |
| 216 | s.closeLocked() |
| 217 | } |
| 218 | |
| 219 | // A missing binary is a deterministic, cheap condition with an |
| 220 | // actionable message — it must NOT trip the breaker. |
| 221 | bin, ok, err := resolveRenderBrowser() |
| 222 | if !ok { |
| 223 | return nil, err |
| 224 | } |
| 225 | if err := s.launchLocked(bin); err != nil { |
| 226 | s.registerFailureLocked() |
| 227 | return nil, err |
| 228 | } |
| 229 | s.consecutiveFailures = 0 |
| 230 | s.touchLocked() |
| 231 | return s.browser, nil |
| 232 | } |
| 233 | |
| 234 | // launchLocked starts Chromium and connects CDP. Callers hold mu. |
| 235 | func (s *renderSession) launchLocked(bin string) error { |