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
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,11 @@ hit. Imported configuration resources are still validated so service wiring
changes invalidate the runtime container. Deployment rollovers can use
`SYMPRESS_KERNEL_BUILD_ID` to force a new cache identity, and
`SYMPRESS_KERNEL_VALIDATE_SOURCE_RESOURCES=1` opts back into source-level
freshness checks when the request-time filesystem cost is acceptable.
freshness checks when the request-time filesystem cost is acceptable. Immutable
release snapshots should set `SYMPRESS_KERNEL_IMMUTABLE_CACHE=1` together with a
build ID: that skips the per-request config and discovery directory scans (about
six to eight filesystem calls per bundle) and makes the build ID the only cache
boundary.

Bundle discovery also stores the matching Composer package manifest under the
kernel cache directory. The manifest is invalidated when Composer metadata such
Expand Down
5 changes: 5 additions & 0 deletions docs/dependency-injection.md
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,11 @@ config, and discovery freshness scans and requires a nonempty
immutable and **every** code/config/Composer change changes that identity. A build
ID alone does not disable normal config validation. Missing identity is an error;
this optimization must never silently hide edits in a mutable installation.
Mutable warm hits otherwise cost one `stat()` per bundle `composer.json` and per
consumed config file plus one directory listing per existing config directory
(about six to eight filesystem calls per bundle), so immutable release
deployments should enable the policy. Runtime's `kernel-cache --generate-build-id`
produces a matching identity.

Bundle extensions are pristine prototypes cloned for each builder. Runtime
compilation copies the mutable definition/argument graph so console lint/debug
Expand Down
5 changes: 4 additions & 1 deletion src/Discovery/KernelPackageManifestCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ final class KernelPackageManifestCache
{
/** @var array<string, array<string, mixed>> */
private array $metadata = [];
private ?ContainerResourceFingerprinter $fingerprints = null;

/** @return array<string, array<string, mixed>> */
public function metadata(): array
Expand Down Expand Up @@ -187,7 +188,9 @@ private function buildIdentity(): string

private function immutable(): bool
{
return (new ContainerResourceFingerprinter((string) $this->projectDir, (string) $this->environment, false))->immutable();
$this->fingerprints ??= new ContainerResourceFingerprinter((string) $this->projectDir, (string) $this->environment, false);

return $this->fingerprints->immutable();
}

private function rootComposerFile(): string
Expand Down
10 changes: 10 additions & 0 deletions src/Kernel/ContainerResourceFingerprinter.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

final class ContainerResourceFingerprinter
{
private ?bool $immutable = null;

public function __construct(
private readonly string $projectDir,
private readonly string $environment,
Expand Down Expand Up @@ -233,14 +235,22 @@ public function shouldValidateCachedSourceResources(): bool

public function immutable(): bool
{
// The policy is read once per fingerprinter; fingerprint() asks for it per bundle.
if ($this->immutable !== null) {
return $this->immutable;
}
$enabled = $_SERVER['SYMPRESS_KERNEL_IMMUTABLE_CACHE'] ?? $_ENV['SYMPRESS_KERNEL_IMMUTABLE_CACHE'] ?? getenv('SYMPRESS_KERNEL_IMMUTABLE_CACHE');
if (filter_var($enabled, FILTER_VALIDATE_BOOL) !== true) {
$this->immutable = false;

return false;
}
$build = defined('SYMPRESS_KERNEL_BUILD_ID') ? constant('SYMPRESS_KERNEL_BUILD_ID') : ($_SERVER['SYMPRESS_KERNEL_BUILD_ID'] ?? $_ENV['SYMPRESS_KERNEL_BUILD_ID'] ?? getenv('SYMPRESS_KERNEL_BUILD_ID'));
if (!is_string($build) || $build === '') {
throw new \RuntimeException('Immutable kernel cache requires an explicit deployment build ID.');
}
$this->immutable = true;

return true;
}

Expand Down
Loading