Accelerator: Spectrum sidecar client
At a glance
Section titled “At a glance”The Accelerator module is the PHP-side client for Spectrum, the optional out-of-process acceleration sidecar. It is a hardened Hypertext Transfer Protocol (HTTP) client with a circuit breaker, JSON Web Token (JWT) capability tokens, one retry for transient faults, and a server-sent events transport for streamed job progress. The engine works without the sidecar. Use this module to inject acceleration without making it required.
Stability: experimental. Spectrum is an optional sidecar, not a frozen public application programming interface (API). The
SpectrumInterfaceit implements is documented as experimental on Contracts / Observability. This client follows that tier. The transport, token format, and budget shape may change between minor versions.
Install
Section titled “Install”composer require nextpdf/core:^3Conceptual overview
Section titled “Conceptual overview”Spectrum offloads processor-heavy work to a local sidecar process, including
hardware detection, Portable Document Format (PDF) parsing, and image
compression. SpectrumClient is a PHP Standards Recommendation 18 (PSR-18)
client that implements the frozen NextPDF\Contracts\SpectrumInterface. It
depends on a ClientInterface, a RequestFactoryInterface, and a
StreamFactoryInterface, not on a hard-wired Hypertext Transfer Protocol (HTTP)
stack.
The client assumes the dependency can fail. A circuit breaker opens after three
consecutive failures. While it is open, isAvailable() returns false for an
exponential backoff window, so a hot path does not keep calling an unavailable
sidecar. The probe result is cached with a time-to-live (TTL). When you
configure an app secret, every outbound request carries a Request Capability
Token. The token is a short-lived HS256 JWT scoped to the endpoint’s required
capabilities. Its lifetime is 120 seconds, or 30 seconds in high-control
authorization mode. Transient 5xx and timeout errors are retried once.
Authentication and parse errors are never retried.
SspectrumClient keeps state per instance. Circuit-breaker state and the probe
cache are not shared. Each PHP FastCGI Process Manager (PHP-FPM) worker should
hold its own instance. Batch results are typed. BatchResult carries
BatchItem entries with a BatchItemStatus, a BatchSummary with a success
rate, and an optional trace ID. HardwareReport and HardwareCapabilities
describe the detected hardware tier. HardwareCapabilities::satisfies() checks
a tier requirement programmatically. The DegradePolicy and
AuthorizationMode enums control capability-loss behavior and token strictness.
The whole module is
@since 2.1.0.
API surface
Section titled “API surface”| Type | Key members | Role |
|---|---|---|
SpectrumClient | isAvailable(), probe(), getBudget(), request() | PSR-18 sidecar client that implements SpectrumInterface |
BatchResult | getItems(), getSummary(), filterByStatus(), traceId() | Typed batch outcome |
BatchItem / BatchItemStatus | isOk(), isSuccessful(), isRetryable() | Per-item result and status enum |
BatchSummary | isFullSuccess(), successRate() | Aggregate batch summary |
HardwareReport | hasPro(), hasEnterprise(), isApiVersionCompatible() | Detected sidecar capabilities |
HardwareCapabilities | hasGpu(), satisfies(), bestAvailableTier() | Programmatic capability branching |
DegradePolicy / AuthorizationMode | enum cases | Degradation behavior and token strictness |
Run composer docs:generate-api-php -- --module=Accelerator to generate the
full PHPDoc table.
Code sample — Quick start
Section titled “Code sample — Quick start”Probe the sidecar through the circuit breaker before you rely on it.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Contracts\SpectrumInterface;
function describeAccelerator(SpectrumInterface $spectrum): string{ if ($spectrum->isAvailable() !== true) { return 'Accelerator unavailable; engine runs in pure-PHP mode.'; }
$report = $spectrum->probe();
return $report->hasEnterprise() ? 'Enterprise accelerator tier active.' : 'Standard accelerator tier active.';}Code sample — Production
Section titled “Code sample — Production”Send a batch through the sidecar when it is healthy, and fall back under the degradation policy when it is not.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Accelerator\DegradePolicy;use NextPDF\Contracts\SpectrumInterface;use Psr\Log\LoggerInterface;
final readonly class AcceleratedCompressor{ public function __construct( private ?SpectrumInterface $spectrum, private DegradePolicy $policy, private LoggerInterface $logger, ) {}
/** @param list<array{id: string, data: string}> $images @return string Raw sidecar body. */ public function compress(array $images): string { if ($this->spectrum?->isAvailable() === true) { return $this->spectrum->request('POST', '/v1/compress', json: ['images' => $images], scope: ['compress']); }
if ($this->policy === DegradePolicy::Strict) { throw new \RuntimeException('Accelerator required under the strict degrade policy.'); }
$this->logger->info('Spectrum unavailable; using PHP image path.');
return ''; }}Edge cases & gotchas
Section titled “Edge cases & gotchas”isAvailable()is a point-in-time, circuit-broken check. Atrueresult can becomefalsebefore the next call. Handle a sidecar that drops between calls.- State for the circuit breaker and probe cache is per instance. Sharing one
SpectrumClientacross workers defeats the breaker. Give each worker its own instance. - Capability tokens are short-lived (120 s, 30 s in high-control mode). A long-running operation must obtain a fresh token, not reuse one.
- Authentication and parse errors are never retried; only transient 5xx responses and timeouts are, and only once. Do not assume idempotent retry beyond that.
- A null
SpectrumInterfaceis a valid “no accelerator” state, not an error. The degrade policy decides whether that is fatal.
Performance
Section titled “Performance”The client adds negligible overhead; the sidecar does the work. The circuit
breaker is the main reliability control. It limits wasted round-trips when the
sidecar is unavailable. The performance_budget of 1500 ms wall / 64 MB peak is
the engine’s reference workload, not a sidecar service-level agreement (SLA).
The reproducibility profile is structural. A batch result carries a trace ID
and timestamps, so two runs differ in those fields.
Security notes
Section titled “Security notes”The sidecar boundary is a trust boundary. When you configure an app secret,
requests carry HS256 capability tokens scoped to the endpoint. Treat that secret
as a credential from a secret manager, and never commit it. High-control
authorization mode shortens token lifetime to 30 seconds for sensitive
endpoints. The operator-supplied sidecar Uniform Resource Locator (URL) is
validated when the configuration is constructed, not at first request: only
http:// and https:// with a non-empty host, or unix:// with a non-empty
socket path, are accepted; any other scheme (gopher://, file://, ftp://,
…) or a network URL without a host fails closed at construction. This is
defense-in-depth against server-side request forgery (SSRF) and unexpected
egress, so a misconfigured endpoint never reaches the HTTP client. Sidecar
responses are external data. Validate them and treat them as untrusted before
they re-enter the engine. The legal-review-required export-control class on
this page reflects that the acceleration feature carries cryptographic
transport and is pending an export-control review. Consult that review before
you redistribute a build that enables it.
Conformance
Section titled “Conformance”This module makes no normative PDF-specification claim. It is an HTTP client for
an internal acceleration protocol. The protocol is engine-defined, not
standardized, so there are no clauses to cite here. Where sidecar work (PDF
parsing, compression) has a conformance dimension, that conformance is
documented on the relevant module page and validated by the oracle and golden
suites in /modules/core/conformance/.
See also
Section titled “See also”- Contracts / Observability — the
SpectrumInterfaceimplemented by this client. - Observability module — runtime-state surface for accelerated work.
- Performance module — budgets for accelerated work.
- Engine security model