| 104 | const healthFailureThreshold = 2 |
| 105 | |
| 106 | type processSupervisor struct { |
| 107 | logger *slog.Logger |
| 108 | engine string |
| 109 | process Process |
| 110 | maxReqLimit int64 |
| 111 | maxQueueSize int64 |
| 112 | maxConcurrency int64 |
| 113 | semaphore chan struct{} |
| 114 | firstStart atomic.Bool |
| 115 | // firstStartMu serializes lazy-launch attempts so concurrent callers do |
| 116 | // not all spawn Launch() simultaneously. Using a mutex (instead of |
| 117 | // sync.Once) lets a failed launch be retried by the next caller, since a |
| 118 | // transient failure (such as a cold-start timeout) must not poison the |
| 119 | // supervisor for the rest of the container's lifetime. See |
| 120 | // https://github.com/gotenberg/gotenberg/issues/1538. |
| 121 | firstStartMu sync.Mutex |
| 122 | reqCounter atomic.Int64 |
| 123 | reqQueueSize atomic.Int64 |
| 124 | restartsCounter atomic.Int64 |
| 125 | isRestarting atomic.Bool |
| 126 | activeTasks atomic.Int64 |
| 127 | restartMutex sync.Mutex |
| 128 | idleShutdownTimeout time.Duration |
| 129 | lastActivity atomic.Int64 // unix nano timestamp of last completed task |
| 130 | // healthMu serializes Healthy() probes so concurrent callers do not |
| 131 | // all issue a CDP roundtrip; the second caller hits the refreshed |
| 132 | // cache instead. |
| 133 | healthMu sync.Mutex |
| 134 | lastHealthyAt atomic.Int64 // unix nano of last successful probe; 0 means never |
| 135 | consecutiveHealthFailures atomic.Int64 // reset to 0 on every successful probe |
| 136 | idleMu sync.Mutex // protects idleStopChan |
| 137 | idleStopChan chan struct{} // signal to stop the idle ticker goroutine |
| 138 | } |
| 139 | |
| 140 | // NewProcessSupervisor initializes a new [ProcessSupervisor]. engine names the |
| 141 | // managed process (for example "chromium" or "libreoffice") and prefixes the |
nothing calls this directly
no outgoing calls
no test coverage detected