Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/advanced/portable-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ $portable = PortableConfig::loadSigned($store->load(), $secret);
$firewall = new Firewall((new Config($cache))->combine($portable));
```

Under classic PHP-FPM each request is a fresh process, so this runs once per request and always reflects the current rules. To avoid querying the database on every request, put a shared cache (APCu, for example) in front of the store.
Under classic PHP-FPM userland state does not carry over between requests, so this runs once per request and always reflects the current rules. To avoid querying the database on every request, put a shared cache (APCu, for example) in front of the store.

### Long-running workers

Expand Down
2 changes: 1 addition & 1 deletion docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ Yes, Phirewall accepts any PSR-16 (PHP Standard Recommendation for Simple Cachin

### Why does InMemoryCache not work in production?

In PHP-FPM (FastCGI Process Manager), each request starts a new process (or reuses one from the pool). The in-memory cache is empty at the start of each request, so counters always reset to zero. This means rate limits and ban counters never accumulate.
In PHP-FPM (FastCGI Process Manager), worker processes are pooled and reused across requests, but PHP tears down userland state at the end of each request. The in-memory cache therefore starts empty on every request, so counters always reset to zero. This means rate limits and ban counters never accumulate.

Under long-running worker runtimes (Swoole, RoadRunner, FrankenPHP worker mode, Octane) the failure is the opposite and easy to miss: the array survives across requests within a worker, so a single-worker demo looks like it "works", but each worker is a separate process with its own array. State is never shared across workers (counters and bans fragment, so the effective rate limit is roughly N times the configured value) and the array grows for the worker's lifetime.

Expand Down
2 changes: 1 addition & 1 deletion docs/features/storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ $config = new Config($cache);
### Characteristics

- Zero external dependencies
- Data resets on every request in PHP-FPM (each request is a new process)
- Data resets on every request in PHP-FPM (userland state does not persist between requests)
- Under long-running worker runtimes (Swoole, RoadRunner, FrankenPHP worker mode, Octane) the array lives for the worker's lifetime: state is **not** shared across workers (each worker is a separate process, so counters and bans fragment) and the array only evicts already-expired entries, so it is not a memory cap. This makes it unsafe as a firewall store there; see the warning below.
- Implements both `CacheInterface` (PSR-16) and `CounterStoreInterface`
- Automatic expired entry purging every 1000 operations
Expand Down
Loading