Skip to content

Commit 5e53748

Browse files
review: address dunglas's review batch
- BackgroundScope -> Scope (and NextScope / WithRequestScope / WithWorkerScope), keeping the type opaque + reusable for other per-server isolation contexts (Mercure hubs, future Prometheus labels). No behaviour change. - $_SERVER['FRANKENPHP_WORKER'] now carries the user-facing worker name instead of "1". The doc has always told callers to rely on presence, not value. Drops the parallel FRANKENPHP_WORKER_NAME injection. - backgroundWorkerReady.abortErr keeps the full error (not just its message), so the wrap chain survives into ensure() callers. - Cap-error wording: drop the Caddyfile-specific "max_threads on the catch-all" phrasing for "increase max threads or declare it as a named worker", to read cleanly when the user is on the JSON config. - Constants merged into a single block; getLookup folds the worker / background-worker handler cases via a small anonymous interface (Go's type switch can't fan out type-asserted access otherwise). - Stub doc nits: third-person godoc ("Declares" / "Returns"). - Test ergonomics: requireSentinelEventually wraps the duplicated Eventually glue; require.NoFileExists, require.ErrorContains, assert.WithinDuration replace ad-hoc combinations. - Renamed background_worker_*_test.go to bgworker*_test.go to match the bgworker.go source file (no underscores in file-name prefixes).
1 parent 03460db commit 5e53748

21 files changed

Lines changed: 360 additions & 439 deletions

background_worker_batch_test.go

Lines changed: 0 additions & 165 deletions
This file was deleted.

bgworker.go

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@ import (
1313
"unsafe"
1414
)
1515

16-
// defaultMaxBackgroundWorkers is the default safety cap for catch-all
17-
// background workers when the user doesn't set max_threads. Caps the
18-
// number of distinct lazy-started instances from a single catch-all.
19-
const defaultMaxBackgroundWorkers = 16
20-
21-
// defaultEnsureTimeout is the default deadline applied when ensure() is
22-
// called without an explicit timeout.
23-
const defaultEnsureTimeout = 30 * time.Second
16+
const (
17+
// defaultMaxBackgroundWorkers is the default safety cap for catch-all
18+
// background workers when the user doesn't set max_threads. Caps the
19+
// number of distinct lazy-started instances from a single catch-all.
20+
defaultMaxBackgroundWorkers = 16
21+
22+
// defaultEnsureTimeout is the default deadline applied when ensure() is
23+
// called without an explicit timeout.
24+
defaultEnsureTimeout = 30 * time.Second
25+
)
2426

2527
// backgroundWorkerReady is the per-instance readiness signal ensure()
2628
// blocks on. ready closes once the worker calls
@@ -32,7 +34,7 @@ type backgroundWorkerReady struct {
3234

3335
aborted chan struct{}
3436
abortOnce sync.Once
35-
abortErr string
37+
abortErr error
3638

3739
// bootFailure carries the most recent pre-readiness crash so a timing-
3840
// out ensure() can report it instead of a generic "didn't call
@@ -67,26 +69,26 @@ func (r *backgroundWorkerReady) markReady() {
6769
// (max_consecutive_failures hit before readiness). Idempotent.
6870
func (r *backgroundWorkerReady) abort(err error) {
6971
r.abortOnce.Do(func() {
70-
r.abortErr = err.Error()
72+
r.abortErr = err
7173
close(r.aborted)
7274
})
7375
}
7476

75-
// BackgroundScope is an opaque per-php_server isolation boundary; the
77+
// Scope is an opaque per-php_server isolation boundary; the
7678
// zero value is the global/embed scope. Obtain values via
77-
// NextBackgroundWorkerScope.
78-
type BackgroundScope uint64
79+
// NextScope.
80+
type Scope uint64
7981

80-
var backgroundScopeCounter atomic.Uint64
82+
var scopeCounter atomic.Uint64
8183

82-
// NextBackgroundWorkerScope returns a fresh scope value. Each php_server
84+
// NextScope returns a fresh scope value. Each php_server
8385
// block should call this once during provisioning.
84-
func NextBackgroundWorkerScope() BackgroundScope {
85-
return BackgroundScope(backgroundScopeCounter.Add(1))
86+
func NextScope() Scope {
87+
return Scope(scopeCounter.Add(1))
8688
}
8789

8890
// backgroundLookups maps scope -> lookup. Scope 0 is the global/embed scope.
89-
var backgroundLookups map[BackgroundScope]*backgroundWorkerLookup
91+
var backgroundLookups map[Scope]*backgroundWorkerLookup
9092

9193
// backgroundWorkerLookup resolves a user-facing worker name to its *worker;
9294
// catchAll is the fallback when byName misses.
@@ -113,8 +115,8 @@ func (l *backgroundWorkerLookup) resolve(name string) *worker {
113115
// lookup. Per-scope name collisions are caught here because bg workers
114116
// intentionally skip the global workersByName map (so two scopes can share
115117
// a user-facing name).
116-
func buildBackgroundWorkerLookups(workers []*worker, opts []workerOpt) (map[BackgroundScope]*backgroundWorkerLookup, error) {
117-
lookups := make(map[BackgroundScope]*backgroundWorkerLookup)
118+
func buildBackgroundWorkerLookups(workers []*worker, opts []workerOpt) (map[Scope]*backgroundWorkerLookup, error) {
119+
lookups := make(map[Scope]*backgroundWorkerLookup)
118120

119121
for i, o := range opts {
120122
if !o.isBackgroundWorker {
@@ -171,17 +173,15 @@ func getLookup(thread *phpThread) *backgroundWorkerLookup {
171173
if backgroundLookups == nil {
172174
return nil
173175
}
174-
var scope BackgroundScope
176+
var scope Scope
175177
if thread != nil {
176-
switch handler := thread.handler.(type) {
177-
case *workerThread:
178-
scope = handler.worker.backgroundScope
179-
case *backgroundWorkerThread:
180-
scope = handler.worker.backgroundScope
181-
default:
182-
if fc, ok := fromContext(thread.context()); ok {
183-
scope = fc.backgroundScope
184-
}
178+
// Both *workerThread and *backgroundWorkerThread expose their *worker
179+
// via this anonymous interface; classic-mode threads don't and fall
180+
// through to the request-context path.
181+
if h, ok := thread.handler.(interface{ scopedWorker() *worker }); ok {
182+
scope = h.scopedWorker().backgroundScope
183+
} else if fc, ok := fromContext(thread.context()); ok {
184+
scope = fc.backgroundScope
185185
}
186186
}
187187
if scope != 0 {
@@ -228,13 +228,13 @@ func ensureBackgroundWorker(thread *phpThread, bgWorkerName string, timeout time
228228

229229
if catchAll.catchAllCap > 0 && len(catchAll.catchAllNames) >= catchAll.catchAllCap {
230230
catchAll.catchAllMu.Unlock()
231-
return fmt.Errorf("cannot start background worker %q: limit of %d reached (increase max_threads on the catch-all background worker or declare it as a named worker)", bgWorkerName, catchAll.catchAllCap)
231+
return fmt.Errorf("cannot start background worker %q: limit of %d reached (increase max threads or declare it as a named worker)", bgWorkerName, catchAll.catchAllCap)
232232
}
233233

234234
t := getInactivePHPThread()
235235
if t == nil {
236236
catchAll.catchAllMu.Unlock()
237-
return fmt.Errorf("no available PHP thread for background worker (increase max_threads)")
237+
return fmt.Errorf("no available PHP thread for background worker (increase max threads)")
238238
}
239239

240240
r := newBackgroundWorkerReady()
@@ -264,7 +264,7 @@ func lazyStartNamedWorker(w *worker) error {
264264
}
265265
t := getInactivePHPThread()
266266
if t == nil {
267-
return fmt.Errorf("no available PHP thread for background worker (increase max_threads)")
267+
return fmt.Errorf("no available PHP thread for background worker (increase max threads)")
268268
}
269269
convertToBackgroundWorkerThread(t, w, w.name, w.backgroundReady)
270270
w.bgLazyStarted = true
@@ -287,7 +287,7 @@ func waitForBackgroundWorkerReady(name string, r *backgroundWorkerReady, timeout
287287
case <-r.ready:
288288
return nil
289289
case <-r.aborted:
290-
return fmt.Errorf("background worker %q failed to start: %s", name, r.abortErr)
290+
return fmt.Errorf("background worker %q failed to start: %w", name, r.abortErr)
291291
case <-timer.C:
292292
return formatEnsureTimeoutError(name, r, timeout)
293293
}

0 commit comments

Comments
 (0)