package frankenphp import ( "fmt" "log/slog" "time" ) // defaultMaxConsecutiveFailures is the default maximum number of consecutive failures before panicking const defaultMaxConsecutiveFailures = 6 // Option instances allow to configure FrankenPHP. type Option func(h *opt) error // WorkerOption instances allow configuring FrankenPHP worker. type WorkerOption func(*workerOpt) error // opt contains the available options. // // If you change this, also update the Caddy module and the documentation. type opt struct { numThreads int maxThreads int workers []workerOpt taskWorkers []workerOpt logger *slog.Logger metrics Metrics phpIni map[string]string maxWaitTime time.Duration } type workerOpt struct { name string fileName string num int env PreparedEnv watch []string maxConsecutiveFailures int isTaskWorker bool maxQueueLen int } // WithNumThreads configures the number of PHP threads to start. func WithNumThreads(numThreads int) Option { return func(o *opt) error { o.numThreads = numThreads return nil } } func WithMaxThreads(maxThreads int) Option { return func(o *opt) error { o.maxThreads = maxThreads return nil } } func WithMetrics(m Metrics) Option { return func(o *opt) error { o.metrics = m return nil } } // WithWorkers configures the PHP workers to start func WithWorkers(name string, fileName string, num int, options ...WorkerOption) Option { return func(o *opt) error { worker := workerOpt{ name: name, fileName: fileName, num: num, env: PrepareEnv(nil), watch: []string{}, maxConsecutiveFailures: defaultMaxConsecutiveFailures, } for _, option := range options { if err := option(&worker); err != nil { return err } } if worker.isTaskWorker { o.taskWorkers = append(o.taskWorkers, worker) } else { o.workers = append(o.workers, worker) } return nil } } // WithWorkerEnv sets environment variables for the worker func WithWorkerEnv(env map[string]string) WorkerOption { return func(w *workerOpt) error { w.env = PrepareEnv(env) return nil } } // WithWorkerWatchMode sets directories to watch for file changes func WithWorkerWatchMode(watch []string) WorkerOption { return func(w *workerOpt) error { w.watch = watch return nil } } // WithWorkerMaxFailures sets the maximum number of consecutive failures before panicking func WithWorkerMaxFailures(maxFailures int) WorkerOption { return func(w *workerOpt) error { if maxFailures < -1 { return fmt.Errorf("max consecutive failures must be >= -1, got %d", maxFailures) } w.maxConsecutiveFailures = maxFailures return nil } } // WithLogger configures the global logger to use. func WithLogger(l *slog.Logger) Option { return func(o *opt) error { o.logger = l return nil } } // WithPhpIni configures user defined PHP ini settings. func WithPhpIni(overrides map[string]string) Option { return func(o *opt) error { o.phpIni = overrides return nil } } // WithMaxWaitTime configures the max time a request may be stalled waiting for a thread. func WithMaxWaitTime(maxWaitTime time.Duration) Option { return func(o *opt) error { o.maxWaitTime = maxWaitTime return nil } } // EXPERIMENTAL: AsTaskWorker configures the worker as a task worker. // no http requests will be handled. // no globals resetting will be performed between tasks. func AsTaskWorker(isTaskWorker bool, maxQueueLen int) WorkerOption { return func(w *workerOpt) error { w.isTaskWorker = isTaskWorker w.maxQueueLen = maxQueueLen return nil } }