← Back to list

What Happens When PHP-FPM Children Die Faster Than They Respawn

When PHP-FPM workers die faster than the master can respawn them, your pool shrinks to zero while the server reports healthy. Here’s the…

Ann R. in CodeX · 2026-05-24 19:26 · 3 claps · 16.9 min read paywalled
#php #php-fpm #programming #software-development #coding-tips
Open on Medium ↗
Wiki topics: 💻 · Programming 👨‍👩‍👧 · Family & Parenting

What Happens When PHP-FPM Children Die Faster Than They Respawn

When PHP-FPM workers die faster than the master can respawn them, your pool shrinks to zero while the server reports healthy. Here’s the fix.

Photo by 愚木混株 Yumu on Unsplash

Photo by 愚木混株 Yumu on Unsplash

The pager goes off at 11:42 PM. The error rate on the checkout service has jumped from baseline (about 0.1%) to 47% in the last four minutes. The on-call engineer SSHs into a production host, looks at the load — 0.4, totally fine. CPU — 12%, idle. Memory — half free. Nothing looks wrong with the box.

systemctl status php8.3-fpm shows the service is running. ps aux | grep php-fpm shows the master process plus four workers. The pool is configured for pm.max_children = 50. Yet only four are alive, and the application logs are full of "504 Gateway Timeout" from nginx.

The engineer checks /var/log/php8.3-fpm.log and finds the pattern. Workers are starting and immediately exiting with signal 11 (SIGSEGV). New workers spawn, take a request, segfault, repeat. The master is dutifully respawning them, but each replacement dies within seconds. The pool size oscillates between 2 and 8 but never recovers to 50. Every incoming request lands in a tiny pool of barely-alive workers and either gets served slowly or times out waiting for a free worker.

The cause turns out to be a corrupted shared memory segment from a recent extension upgrade. The fix is a full FPM restart. But the diagnosis took 47 minutes because the failure mode looked like “the server is fine, the application is broken” — and the team had never seen what happens when worker respawn can’t keep up with worker death.

What follows is the anatomy of FPM worker lifecycle: how respawn actually works, why it sometimes fails, and the small set of configuration choices that decide whether your pool recovers from a bad day or stays in a death spiral until someone manually intervenes.

TL;DR Speedrun

  • PHP-FPM workers can die for many reasons: clean cycling (pm.max_requests), memory limits, segfaults, OOM killer, runtime errors that escape. The master respawns them. Most of the time this is invisible.
  • Respawn is fast (~10–20ms per worker on a modern host) but the master is single-threaded for spawn handling. The pool’s maximum sustainable death rate is roughly 1000ms / spawn_time_ms workers per second.
  • When death rate exceeds respawn rate, the pool shrinks toward zero. Every request lands in a tiny set of barely-alive workers. From the outside it looks like “the server is up but slow.”
  • emergency_restart_threshold is the safety net — when too many workers die in a short window, the entire FPM master restarts. Disabled by default, must be configured explicitly.
  • The metric to watch isn’t just CPU or memory — it’s pool.max_children_reached and the FPM error log's "child exited on signal" frequency. Both are quiet until the day they're not.

What You’ll Learn

  • The full lifecycle of an FPM worker from spawn to death, including the four common ways they die
  • The math behind respawn capacity and when it breaks down
  • The emergency_restart_threshold setting that prevents the worst death spirals
  • How to read FPM logs to distinguish “normal death” from “we have a problem”
  • Pool sizing patterns that survive bad deploys instead of cascading into outage

The Worker Lifecycle

A PHP-FPM master process is a babysitter. It spawns child workers, hands each new HTTP request to an idle worker, and watches for child deaths so it can respawn replacements. The master itself never serves a request; its only job is process management.

Each child handles requests in a loop:

1. Accept connection from the listen socket
2. Read FastCGI protocol headers
3. Execute the PHP script
4. Send response back over FastCGI
5. Go back to step 1

A child can die at any point. The master finds out via SIGCHLD (the kernel notifies parents when child processes terminate), reads the exit reason from waitpid(), logs it, and decides whether to spawn a replacement. The whole flow takes single-digit milliseconds in a healthy system.

Verified on PHP 8.3 with a 4-worker pool:

$ kill -9 $WORKER_PID
[fpm log]: WARNING: [pool www] child 1499 exited on signal 9 (SIGKILL) after 17.97 seconds from start
[fpm log]: NOTICE: [pool www] child 1563 started

Master detected the kill within milliseconds and spawned a replacement. Production behavior is identical — workers cycle, replacements appear, the application keeps serving requests.

The interesting question is what happens when this loop can’t keep up.

How Workers Actually Die

Four common death modes, each with different implications.

Clean cycling via pm.max_requests. This is the intentional kind. Set pm.max_requests = 500 and each worker exits after handling 500 requests, getting replaced by a fresh one. This is how PHP-FPM mitigates memory leaks in long-running workers — bad code that grows memory by 1KB per request eventually exits and starts fresh. Cycling is graceful (the worker finishes its current request first), the death is logged at NOTICE level, and the respawn is immediate.

PHP memory exhaustion. A script hits its memory_limit (default usually 128M-512M). PHP throws a fatal error, the request returns 500, and the worker keeps running. This is a critical distinction many engineers miss — memory_limit is per-request, enforced by PHP itself, and doesn't kill the worker process. Verified with FPM running, sending a request that exceeds memory_limit:

PHP Fatal error: Allowed memory size of 33554432 bytes exhausted...
Status: 500 Internal Server Error
[worker count unchanged - same PIDs still alive]

Memory exhaustion is a request-level error, not a worker-level death.

Segmentation faults. A C-extension bug, a stack overflow, a corrupted opcache entry — these terminate the worker process via SIGSEGV (signal 11). The current request dies mid-flight (the client sees a 502 or a connection reset). The master detects the death and respawns. Logged as:

WARNING: [pool www] child 1714 exited on signal 11 (SIGSEGV) after 15.78 seconds from start

Segfaults are usually rare and bug-specific. Common triggers: badly-written C extensions, deep recursion exceeding stack limits, or interactions between opcache and extensions that don’t handle persistent memory cleanly.

OOM killer. When the host runs out of memory (not the PHP per-request limit), the Linux OOM killer picks a process to terminate. FPM workers are often the chosen victim because they’re large memory consumers. The kill is SIGKILL (signal 9), so the worker has no chance to clean up. The master respawns, but if memory pressure persists, the next worker meets the same fate. Often cascades into a death spiral.

The first three modes are routine; the fourth tends to escalate. All four log differently, which matters for diagnosis.

The Respawn Math

Measured on a small test pool: spawning a new worker takes 7–17ms. The variance is mostly initialization work (loading opcache, running pool startup scripts, opening shared resources). For a typical production pool, 15ms per spawn is a reasonable estimate.

The master is single-threaded for spawn handling. It processes one SIGCHLD at a time, calls waitpid, decides whether to respawn, calls fork+exec. The next SIGCHLD waits. This means the absolute ceiling on respawn rate is roughly:

max_respawn_per_second = 1000 / spawn_time_ms
                       = 1000 / 15
                       ≈ 67 workers per second

Most of the time this is enormous headroom. Normal worker cycling — say, 1000 requests per worker before recycling, at 100 requests per second — means 1 worker death every 10 seconds. The respawn capacity is 600× what’s needed.

But the gap can close. Consider the scenarios:

Normal:          0.1 deaths/sec  →  Respawn ratio: 0.0015 (stable)
Memory pressure: 5 deaths/sec    →  Respawn ratio: 0.075  (stable)
Bad deploy:      50 deaths/sec   →  Respawn ratio: 0.75   (stable, but close)
Cascading:       200 deaths/sec  →  Respawn ratio: 3.0    (death spiral)

The death spiral happens when worker death rate exceeds respawn capacity. Even when the underlying problem (bad deploy, runaway extension) stops, the pool can’t recover its own size because each new worker dies before being replaced.

The corner case is workers that die during startup. If the bootstrap process itself crashes — for instance, the application’s autoloader fails because a deployed file is missing — every spawned worker dies before processing a single request. Verified in test:

WARNING: [pool www] child 1757 exited on signal 11 (SIGSEGV) after 0.0019 seconds from start
ERROR: [pool www] child failed to initialize

The “child failed to initialize” log line is the smoking gun. It means the worker died fast enough that FPM marks it as never having become operational. A few of these is normal during a crash bug. Hundreds in a minute means the pool is in trouble.

Emergency Restart Threshold

PHP-FPM has a built-in escape hatch for the death spiral: emergency_restart_threshold. When this many workers die within emergency_restart_interval, the entire FPM master restarts, clearing whatever state caused the chain of failures.

; /etc/php/8.3/fpm/php-fpm.conf
emergency_restart_threshold = 10
emergency_restart_interval = 1m

Verified behavior: with emergency_restart_threshold = 3 and interval = 30s, after triggering 3 SIGSEGV deaths in rapid succession:

WARNING: failed processes threshold (3 in 30 sec) is reached, initiating reload

The master tears down and restarts. New workers spawn cleanly into the reset state. If the underlying problem persists (genuinely corrupted opcache, bad extension), the cycle can recur — but the act of reloading often clears transient issues (stale shared memory, broken socket state, OOM-induced cleanup) that would otherwise have stuck the pool indefinitely.

This setting is disabled by default. Most stock PHP-FPM installs ship without it configured. The reasoning is probably “we don’t want surprise restarts.” The cost of leaving it off is that the worst failure mode — the slow, partial death spiral that doesn’t trigger any monitoring alert — runs unchecked until a human notices.

Recommended values for production:

emergency_restart_threshold = 10    ; tolerate normal failures
emergency_restart_interval = 1m     ; over what window
process_control_timeout = 10s       ; how long graceful shutdown can take

Higher threshold avoids restart loops from normal transient errors. Lower threshold (3–5) reacts faster to real cascades. The right value depends on baseline death rate during normal operation.

Pool Sizing That Survives a Bad Day

The naive way to size pm.max_children is "total RAM divided by per-worker memory." Take 8GB of available memory, assume 100MB per worker, set max_children = 80. This sizes for happy-path throughput and ignores failure modes.

The better mental model: size to survive temporary problems while maintaining baseline capacity.

; A pool designed to survive cascades
pm = dynamic
pm.max_children = 50          ; ceiling for normal operation
pm.start_servers = 10         ; warm pool from boot
pm.min_spare_servers = 5      ; always keep this many ready
pm.max_spare_servers = 20     ; trim back during low load
pm.max_requests = 500         ; cycle workers to limit memory growth
pm.process_idle_timeout = 60s ; idle workers retire after this

Three principles encoded here:

**pm.max_requests** caps how many requests each worker handles before cycling. A small value (100) recycles aggressively, keeping memory usage bounded but increasing baseline death rate. A large value (10000) reduces respawn activity but tolerates memory growth. Most teams land between 500 and 2000.

**pm.min_spare_servers** prevents the pool from shrinking to nothing during quiet periods. Even at low traffic, the pool maintains warm workers ready to absorb a sudden burst. Without this, traffic spikes hit a cold pool and spawn-storm.

**pm.start_servers** initializes the pool with enough workers to handle baseline load immediately, instead of ramping up. A boot that starts with pm.start_servers = 2 takes time to scale up under traffic; one with start_servers = 10 is ready immediately.

The interaction matters. start_servers should be roughly min_spare_servers + average_concurrent_load. If average load is 5 simultaneous requests and you want 5 spares, start with 10. Anything less and the pool spends the first minutes of every reboot scaling up while requests time out waiting for free workers.

The Memory Pressure Cascade

The most common death spiral pattern in production isn’t a code bug — it’s gradual memory growth that eventually crosses a threshold and triggers the OOM killer.

The sequence:

T+0:    Pool of 50 workers, each using ~80MB → 4GB total
T+30m:  Average per-worker memory grows to ~120MB → 6GB total
T+45m:  System memory pressure starts, swap activity begins
T+47m:  OOM killer terminates the largest FPM worker
T+47m:  Master respawns the worker (fresh, low memory)
T+48m:  Three more workers killed in rapid succession
T+48m:  Pool oscillating between 30 and 50 active workers
T+50m:  emergency_restart_threshold triggers (if configured)
T+50m:  Full master restart, pool resets to baseline memory

Without emergency_restart_threshold, the pool spends hours in an oscillating partial state. Some requests succeed (workers that survive long enough), some time out (waiting for free workers), error rates oscillate around 5-30%. Monitoring alerts on error rate but not on root cause.

The structural fix is pm.max_requests set low enough that workers cycle out before memory growth becomes a problem. If average worker memory grows by 100KB per request, and you want to cap workers at 200MB, that's 2000 requests per worker. Set pm.max_requests = 1500 to recycle with margin. Each recycled worker resets to baseline memory.

The other fix is monitoring: watch per-worker RSS over time, alert when the trend predicts crossing physical memory before the next deploy. The OOM cascade isn’t a surprise if you’re tracking the trend.

Reading the FPM Logs

The error log is the diagnostic surface. Three patterns to recognize:

Routine cycling. Workers exit at the request limit, master respawns:

NOTICE: [pool www] child 1234 started
[after 500 requests]
NOTICE: [pool www] child 1234 exiting on max_requests
NOTICE: [pool www] child 1567 started

Logged at NOTICE. Volume is roughly total_requests / pm.max_requests deaths per period.

Abnormal death. A worker dies via signal (segfault, OOM kill, manual kill):

WARNING: [pool www] child 1234 exited on signal 11 (SIGSEGV) after 145.23 seconds from start
NOTICE: [pool www] child 1789 started

Logged at WARNING. Should be rare in healthy systems. Frequent SIGSEGV almost always means an extension bug or stack overflow in application code.

Death during startup. The worker exits before becoming operational:

WARNING: [pool www] child 1234 exited on signal 11 (SIGSEGV) after 0.002 seconds from start
ERROR: [pool www] child failed to initialize

The “child failed to initialize” line means the bootstrap process itself is broken. Very different from a worker that crashed mid-request. Trigger: typically a missing file in deploy, broken autoloader configuration, or extension that fails to load.

Emergency restart triggered. The threshold has been crossed:

WARNING: failed processes threshold (10 in 1 min) is reached, initiating reload
NOTICE: Reloading in progress ...
NOTICE: reloading: execvp("/usr/sbin/php-fpm8.3", {...})

The master is performing a planned restart. New worker pool will spawn from the reset state. Disruption is small (a few seconds of degraded service) compared to the alternative.

Centralized log aggregation (ELK, Loki, Datadog) should index these messages with structured filters. Alerts on rate of “exited on signal” or “child failed to initialize” catch death spirals before they trigger emergency restarts — which means catching them while there’s still time to roll back the bad deploy that caused them.

Pitfalls to Avoid

Confusing memory_limit with worker death. memory_limit is per-request — when exceeded, the request fails but the worker survives. Reading "PHP Fatal error: Allowed memory size exhausted" in logs doesn't mean the pool is unhealthy; it means specific requests are too memory-hungry. Worker deaths show up as "exited on signal" entries, not as PHP fatals.

Setting pm.max_children based on RAM only. RAM constraint is necessary but not sufficient. max_children = 200 with database connection pool capped at 50 means 150 workers will queue waiting for database connections, holding FPM worker slots without making progress. Size max_children to the minimum of (RAM / per-worker memory, database connection limit, downstream service capacity).

Disabling pm.max_requests. Set to 0, workers never cycle. Memory leaks accumulate forever. The pool eventually exhausts host memory, OOM killer cascades, full outage. Some teams disable cycling because "it's unnecessary churn" — they're optimizing for the happy path and breaking the failure recovery path. Always cycle.

Leaving emergency_restart_threshold disabled. Default is no threshold, meaning no self-healing for cascade failures. Set it. The cost of a spurious restart is small (a few seconds of brief degradation); the cost of an unhandled death spiral is hours of partial outage requiring manual intervention.

Ignoring request_terminate_timeout. This kills requests that exceed the timeout. Without it, a slow request can hold a worker indefinitely — a leaked database connection, a hung HTTP call to a downstream service. The worker stays "busy" forever, pool capacity shrinks, healthy requests time out. Set it to something below your load balancer timeout (usually 30s or 60s).

Trusting Kubernetes liveness probes alone. Kubernetes restarts pods when liveness probes fail. The probe usually checks “does FPM accept connections?” which stays true even when the pool is in a death spiral with only 2 of 50 workers alive. Liveness probes don’t catch partial degradation. Pool-level metrics (status endpoint, log scraping) catch what liveness probes miss.

Mini Q&A

How do I see current FPM pool status in production?

Enable pm.status_path in the pool config (e.g., pm.status_path = /fpm-status), then route nginx to forward requests for that path to FPM. Hitting /fpm-status returns counts of idle/active/total processes, accepted connections, and crucially, max children reached — the count of times the pool hit its ceiling. That metric should ideally be 0; non-zero means you're under-provisioned. Add ?full for per-worker details including the current request and how long it's been running.

What’s the difference between pm = dynamic, static, and ondemand?

static: fixed pool size, workers always alive. Predictable memory usage, no spawn latency. Wastes resources during low load. dynamic: pool size varies between min_spare_servers and max_children based on load. Balanced default for most workloads. ondemand: workers spawn only when a request arrives, exit when idle for pm.process_idle_timeout. Saves memory on low-traffic apps, adds spawn latency to first requests. For production web apps, dynamic is almost always the right choice.

Should I use Roadrunner or Swoole instead of FPM to avoid this?

Different trade-off, not a strict upgrade. Roadrunner and Swoole run PHP as long-lived workers without the spawn-per-request model, eliminating respawn entirely. They’re significantly faster for high-throughput APIs and avoid the death spiral class of problems. The cost: every memory leak, every global state mistake, every shared resource bug is now a long-term problem instead of getting cleaned up at request boundaries. For most applications, FPM with proper configuration is simpler and adequate. For high-throughput services where every millisecond counts, the alternative runtime is worth the operational complexity.

Will Kubernetes Horizontal Pod Autoscaler handle this?

Partially. HPA scales pods based on CPU or custom metrics; it doesn’t see per-pool worker health inside a pod. A pod with FPM in a death spiral has near-zero CPU (workers can’t run if they keep dying), which HPA reads as “low load” — exactly wrong. HPA can scale pods up under load, but it can’t detect a sick pod. The right monitoring is FPM-pool-level metrics (status endpoint scraping, log-based alerts), not just pod-level CPU.

Should pm.max_children be different for different routes?

You can’t configure that directly in a single FPM pool, but you can run multiple pools (admin pool, API pool, queue worker pool) with different settings each. Each pool has its own pm.max_children, its own listen socket, its own resource profile. Route nginx upstreams to different sockets based on URL pattern. This isolates fast-and-cheap routes from slow-and-expensive ones — a death spiral in the admin pool doesn't kill the API pool.

Wrap-Up

FPM worker management is the kind of infrastructure detail that runs invisibly until the day it doesn’t. Most teams never see a death spiral; the pool’s normal operation is robust enough that bad deploys, memory pressure, and the occasional segfault get absorbed without anyone noticing. The day it does fail, the failure mode is unfamiliar — the server is up, the load is low, the application is on fire — and the diagnosis takes longer than it should because nobody on the team has seen it before.

The configuration that prevents the worst outcomes is small and well-defined. pm.max_requests low enough to cycle out memory growth before it accumulates. emergency_restart_threshold enabled with a reasonable window. Pool sizing that accounts for downstream service limits, not just RAM. Monitoring that watches pool-level metrics (max children reached, worker death rate from logs) instead of just pod-level resource usage.

Most production PHP-FPM deployments ship with stock configuration and never tune it because nothing’s gone wrong yet. The cost of pre-tuning is small — half a day reviewing pool settings against the application’s actual behavior. The cost of post-tuning, mid-incident, is whatever the outage costs.

Closing Loop

The pager goes off at 11:42 PM. Error rate on the checkout service has jumped from 0.1% to 47%. The on-call engineer checks the dashboards.

The new dashboard added six months ago — pool-level FPM metrics, scraped from /fpm-status every 10 seconds — shows what's happening immediately. The max_children_reached counter has been incrementing every minute for the last six minutes. The pool size is oscillating between 4 and 8 against a ceiling of 50. The FPM error log query (the one wired into the alert) shows 200+ child exited on signal 11 entries in the last 10 minutes.

The on-call rolls back the deploy that landed at 11:34. Within 90 seconds, worker death rate drops to baseline. The pool refills to 50. Error rate returns to 0.1%. Total time from page to resolution: 14 minutes. The death spiral that took 47 minutes to diagnose the first time gets diagnosed in 3 minutes the second time, because the team learned to instrument the pool itself, not just the server it runs on.

The lesson sticks. The runbook gets a new entry. The metrics are part of the standard dashboard going forward. The next time it happens — and there will be a next time — it’s a 5-minute incident instead of an hour.

“People Also Ask”

1. What does child exited on signal 11 (SIGSEGV) mean in PHP-FPM logs? The worker process crashed with a segmentation fault. Common causes: a buggy PHP extension, stack overflow from deep recursion, corrupted opcache shared memory, or hardware/kernel-level memory corruption. The current request being processed dies; the master spawns a replacement. Occasional SIGSEGVs are tolerable; frequent ones indicate a specific bug to track down, usually in an extension or in code that exercises an extension's edge case.

2. How is PHP memory_limit different from a worker dying? memory_limit is enforced by PHP itself per-request. When a script exceeds it, PHP throws a fatal error and returns HTTP 500, but the worker process continues to serve more requests. Workers die when something kills them at the OS level: SIGSEGV (crash), SIGKILL from OOM killer (host out of memory), or pm.max_requests cycling. Reading "Allowed memory size exhausted" in logs doesn't mean the pool is sick; it means specific requests need more memory than allowed.

3. What’s the right value for pm.max_requests in PHP-FPM? Between 500 and 2000 for most production applications. Lower values (100) cycle workers aggressively, which limits memory growth but increases respawn overhead. Higher values (5000+) reduce respawn but tolerate more memory accumulation. Test with realistic traffic: if average worker memory grows steadily over its lifetime, set max_requests low enough that workers cycle before crossing a memory threshold. Never set to 0 (no cycling) in production — that's how memory leaks become outages.

4. How do I detect a PHP-FPM death spiral? Watch three signals: the max children reached counter from the FPM status endpoint (should be 0 in healthy operation), the rate of "child exited on signal" entries in the error log (should be near zero), and the gap between configured pm.max_children and actual active worker count. When workers are dying faster than spawning, total worker count stays well below the ceiling despite the pool being saturated. Standard monitoring tools (Datadog APM, New Relic, Prometheus with exporter) can scrape these metrics.

5. What does emergency_restart_threshold do? When more than N workers die within emergency_restart_interval, the entire FPM master restarts itself, clearing whatever state caused the chain of failures. It's the safety net for death spirals that can't recover otherwise. Disabled by default; recommended setting is emergency_restart_threshold = 10 and emergency_restart_interval = 1m. The brief disruption during restart is preferable to indefinite partial outage.

6. Should I use static or dynamic process manager in PHP-FPM? Dynamic for almost all production web applications. Static (fixed pool size) wastes memory during low load and provides no benefit on steady traffic. Ondemand (spawn on request) saves memory but adds spawn latency to first requests, which hurts user-facing services. Dynamic balances both — pool size varies between min_spare_servers and max_children based on actual load. Reserve static for specific cases like dedicated batch-processing pools.

7. How does Kubernetes interact with PHP-FPM pool health? Kubernetes operates at pod granularity; FPM operates at worker granularity within a pod. Kubernetes liveness probes check “does FPM accept connections?” which stays true even when 48 of 50 workers are dead. Pod-level CPU and memory metrics don’t reveal pool-internal health. Kubernetes can scale pods but can’t detect a degraded pod. Production deployments should expose FPM status metrics (via sidecar or in-pod exporter) for proper pool-health monitoring on top of Kubernetes.

8. What’s the difference between pm.max_children and the number of available CPU cores? They're related but not the same. pm.max_children is the maximum concurrent workers. CPU cores determine how many can run truly in parallel. A pool with max_children = 100 on a 4-core host has 100 workers but only 4 running at any instant; the rest are blocked on I/O (database, cache, HTTP calls). Most PHP applications are I/O-bound, so max_children higher than core count is normal and correct. Size max_children to (RAM available / per-worker memory) and (downstream service connection limit), not to core count.

Note: All measurements in this article were performed against actual PHP-FPM 8.3.6 on Ubuntu 24.04. Respawn timing (7–17ms per worker) varies with hardware, opcache configuration, and pool startup scripts; production servers should measure their own respawn latency rather than relying on these specific numbers. The “child failed to initialize” log pattern is consistent across PHP 7.x and 8.x; the emergency_restart_threshold behavior is stable across versions. Tuning recommendations should be validated against your application's actual traffic patterns and downstream service constraints before deploying to production.


메타데이터
post_id
d016afd319e7
slug
what-happens-when-php-fpm-children-die-faster-than-they-respawn-d016afd319e7
url
https://medium.com/codex/what-happens-when-php-fpm-children-die-faster-than-they-respawn-d016afd319e7
canonical_url
https://medium.com/codex/what-happens-when-php-fpm-children-die-faster-than-they-respawn-d016afd319e7
author_url
https://medium.com/@annxsa
status
ok
fetched_at
2026-06-09 14:34:10