@@ -6,8 +6,10 @@ import (
66 "fmt"
77 "os"
88 "path/filepath"
9+ "runtime"
910 "strings"
1011 "sync"
12+ "sync/atomic"
1113 "time"
1214
1315 "github.com/dunglas/frankenphp/internal/fastabs"
@@ -28,6 +30,7 @@ type worker struct {
2830 maxConsecutiveFailures int
2931 onThreadReady func (int )
3032 onThreadShutdown func (int )
33+ queuedRequests atomic.Int32
3134}
3235
3336var (
@@ -253,24 +256,30 @@ func (worker *worker) isAtThreadLimit() bool {
253256func (worker * worker ) handleRequest (ch contextHolder ) error {
254257 metrics .StartWorkerRequest (worker .name )
255258
256- // dispatch requests to all worker threads in order
257- worker .threadMutex .RLock ()
258- for _ , thread := range worker .threads {
259- select {
260- case thread .requestChan <- ch :
261- worker .threadMutex .RUnlock ()
262- <- ch .frankenPHPContext .done
263- metrics .StopWorkerRequest (worker .name , time .Since (ch .frankenPHPContext .startedAt ))
259+ runtime .Gosched ()
264260
265- return nil
266- default :
267- // thread is busy, continue
261+ if worker .queuedRequests .Load () == 0 {
262+ // dispatch requests to all worker threads in order
263+ worker .threadMutex .RLock ()
264+ for _ , thread := range worker .threads {
265+ select {
266+ case thread .requestChan <- ch :
267+ worker .threadMutex .RUnlock ()
268+ <- ch .frankenPHPContext .done
269+ metrics .StopWorkerRequest (worker .name , time .Since (ch .frankenPHPContext .startedAt ))
270+
271+ return nil
272+ default :
273+ // thread is busy, continue
274+ }
268275 }
276+ worker .threadMutex .RUnlock ()
269277 }
270- worker .threadMutex .RUnlock ()
271278
272279 // if no thread was available, mark the request as queued and apply the scaling strategy
280+ worker .queuedRequests .Add (1 )
273281 metrics .QueuedWorkerRequest (worker .name )
282+
274283 for {
275284 workerScaleChan := scaleChan
276285 if worker .isAtThreadLimit () {
@@ -279,6 +288,7 @@ func (worker *worker) handleRequest(ch contextHolder) error {
279288
280289 select {
281290 case worker .requestChan <- ch :
291+ worker .queuedRequests .Add (- 1 )
282292 metrics .DequeuedWorkerRequest (worker .name )
283293 <- ch .frankenPHPContext .done
284294 metrics .StopWorkerRequest (worker .name , time .Since (ch .frankenPHPContext .startedAt ))
@@ -288,7 +298,9 @@ func (worker *worker) handleRequest(ch contextHolder) error {
288298 // the request has triggered scaling, continue to wait for a thread
289299 case <- timeoutChan (maxWaitTime ):
290300 // the request has timed out stalling
301+ worker .queuedRequests .Add (- 1 )
291302 metrics .DequeuedWorkerRequest (worker .name )
303+ metrics .StopWorkerRequest (worker .name , time .Since (ch .frankenPHPContext .startedAt ))
292304
293305 ch .frankenPHPContext .reject (ErrMaxWaitTimeExceeded )
294306
0 commit comments