feat: eagerly auto restart processes (#916)

* Fix auto-restart's initial number of requests
It would need 1 less requests on the first restart
The number of request was technically off by one after the first restart

* Supervisor now eagerly restarts processes
When the maxReqLimit is reached, restart the process in the background

* Update pkg/gotenberg/supervisor.go

Co-authored-by: Julien Neuhart <neuhart.julien@gmail.com>

---------

Co-authored-by: Julien Neuhart <neuhart.julien@gmail.com>
This commit is contained in:
Maxime Lapointe
2024-07-02 12:29:57 -04:00
committed by GitHub
parent b1e69a9059
commit 2baba67bfc
2 changed files with 26 additions and 11 deletions

View File

@@ -187,10 +187,13 @@ func (s *processSupervisor) Run(ctx context.Context, logger *zap.Logger, task fu
logger.Debug("process lock acquired") logger.Debug("process lock acquired")
s.reqQueueSize.Add(-1) s.reqQueueSize.Add(-1)
s.reqCounter.Add(1) s.reqCounter.Add(1)
releaseMutexChan := true
defer func() { defer func() {
logger.Debug("process lock released") if releaseMutexChan {
<-s.mutexChan logger.Debug("process lock released")
<-s.mutexChan
}
}() }()
if !s.firstStart.Load() { if !s.firstStart.Load() {
@@ -212,18 +215,26 @@ func (s *processSupervisor) Run(ctx context.Context, logger *zap.Logger, task fu
} }
} }
err := s.runWithDeadline(ctx, task)
if s.maxReqLimit > 0 && s.reqCounter.Load() >= s.maxReqLimit { if s.maxReqLimit > 0 && s.reqCounter.Load() >= s.maxReqLimit {
s.logger.Debug("max request limit reached, restarting...") s.logger.Debug("max request limit reached, restarting eagerly...")
err := s.runWithDeadline(ctx, func() error { releaseMutexChan = false
return s.restart()
}) go func() {
if err != nil { err := s.runWithDeadline(context.Background(), func() error {
return fmt.Errorf("process restart before task: %w", err) return s.restart()
} })
if err != nil {
s.logger.Error(fmt.Sprintf("process restart after task: %v", err))
}
logger.Debug("process lock released")
<-s.mutexChan
}()
} }
// Note: no error wrapping because it leaks on Chromium console exceptions output. // Note: no error wrapping because it leaks on Chromium console exceptions output.
return s.runWithDeadline(ctx, task) return err
case <-ctx.Done(): case <-ctx.Done():
logger.Debug("failed to acquire process lock before deadline") logger.Debug("failed to acquire process lock before deadline")
s.reqQueueSize.Add(-1) s.reqQueueSize.Add(-1)

View File

@@ -325,7 +325,7 @@ func TestProcessSupervisor_Run(t *testing.T) {
expectedStopCalls: 1, expectedStopCalls: 1,
}, },
{ {
scenario: "cannot restart after reaching max request limit", scenario: "auto-restart after reaching max request limit",
startError: errors.New("start error"), startError: errors.New("start error"),
initiallyStarted: true, initiallyStarted: true,
isRestarting: false, isRestarting: false,
@@ -451,6 +451,10 @@ func TestProcessSupervisor_Run(t *testing.T) {
return return
} }
// Making sure restarts are finished.
ps.mutexChan <- struct{}{}
<-ps.mutexChan
if startCalls.Load() != tc.expectedStartCalls { if startCalls.Load() != tc.expectedStartCalls {
t.Errorf("expected %d process.Start calls, got %d", tc.expectedStartCalls, startCalls.Load()) t.Errorf("expected %d process.Start calls, got %d", tc.expectedStartCalls, startCalls.Load())
} }