Pro edycja
Stream — pełna dokumentacja referencyjna
W skrócie
Dział zatytułowany „W skrócie”Ta strona dokumentuje publiczne kontrakty, klasy, metody i tryby awarii podsystemu NextPDF\Pro\Stream wykraczające poza stronę przeglądową. Każdy poniższy typ jest częścią udokumentowanej publicznej powierzchni Pro.
Dostępność i licencjonowanie
Dział zatytułowany „Dostępność i licencjonowanie”Ta funkcja jest dostarczana w NextPDF Pro (nextpdf/pro) i aktywuje się wraz z kopertą licencyjną poziomu Pro. Wdrożenie bez tego uprawnienia nie ładuje klas tej funkcji. Porównaj edycje i uzyskaj licencję.
Nie obowiązuje żadna flaga licencji na poziomie pojedynczej funkcji; kod jest dostarczany z edycją Pro. Liczba pracowników, rozmiar partii, budżet ponowień oraz backend magazynu to parametry czasu działania.
Architektura: zamrożony szew silnika
Dział zatytułowany „Architektura: zamrożony szew silnika”NextPDF\Pro\Stream\Engine\RenderEngineInterface to kontrakt między silnikiem przepustowości a procesorem strumienia zadań dokumentowych. Silnik go implementuje (zarządzając współbieżnością, cyklem życia puli pracowników, przeciwciśnieniem (backpressure), ograniczoną pamięcią); procesor strumienia go konsumuje (zarządzając stanem z kluczami, deduplikacją, ponawianiem, punktami kontrolnymi i zatwierdzaniem dokładnie raz). Silnik zwraca bajty wraz z sha-256, nigdy zatwierdzonej lokalizacji — to właśnie ta wolność od skutków ubocznych pozwala procesorowi przygotować, zatwierdzić i utworzyć punkt kontrolny dokładnie raz.
public function renderBatch(array $manifests, array $variablesByJobId = []): array; // list<EngineRenderResult>, input orderpublic function maxBatchSize(): int; // int<1, max> backpressure hintpublic function isAvailable(): bool;$manifests to list<RenderManifest> o rozmiarze co najwyżej maxBatchSize(); $variablesByJobId mapuje identyfikator zadania na zmienne szablonu array<string, scalar>. Niepowodzenie pojedynczego manifestu to wynik Failed/Timeout dla danego elementu i nigdy nie przerywa partii.
Silniki
Dział zatytułowany „Silniki”NextPDF\Pro\Stream\Engine\InProcessRenderEngine
Dział zatytułowany „NextPDF\Pro\Stream\Engine\InProcessRenderEngine”Synchroniczny, jednoprocesowy punkt odniesienia. Waliduje każdy manifest w trybie fail-closed za pomocą RenderManifestValidator (limit 16 MiB ładunku inline, listy dozwolonych dla zgodności/podpisu, format skrótu treści sha-256, składnia lokalizacji BCP-47) przed renderowaniem przez SingleDocumentRenderer z Core. Blokujący błąd walidacji powoduje zwarcie do EngineRenderResult::failed(jobId, 'SPEC-MANIFEST-INVALID', ...); wyjątek renderowania staje się 'SPEC-RENDER-EXCEPTION'. Konstruktor: __construct(SingleDocumentRenderer $renderer, int $maxBatchSize = 64, ?RenderManifestValidator $validator = null) — maxBatchSize < 1 zgłasza InvalidArgumentException. isAvailable() jest zawsze true.
NextPDF\Pro\Stream\Engine\ConcurrentRenderEngine
Dział zatytułowany „NextPDF\Pro\Stream\Engine\ConcurrentRenderEngine”final readonly, __construct(RenderUnitExecutorInterface $executor). Opakowuje każdy manifest w indeksowany RenderUnit, uruchamia je przez wykonawcę i ponownie sortuje ukończenia według indeksu, więc wynik jest bajtowo identyczny z renderowaniem sekwencyjnym. Indeks ukończenia spoza [0, count) zgłasza RenderEngineException::unknownUnit(); powtórzony indeks zgłasza duplicateResult(); brakujący indeks zgłasza missingResult(). maxBatchSize() i isAvailable() delegują do wykonawcy.
Wykonawcy
Dział zatytułowany „Wykonawcy”NextPDF\Pro\Stream\Engine\RenderUnitExecutorInterface
Dział zatytułowany „NextPDF\Pro\Stream\Engine\RenderUnitExecutorInterface”public function execute(array $units): iterable; // iterable<CompletedRenderUnit>, any orderpublic function maxBatchSize(): int;public function isAvailable(): bool;Implementacje mogą zwracać ukończenia w dowolnej kolejności; ConcurrentRenderEngine odtwarza kolejność według indeksu.
NextPDF\Pro\Stream\Engine\InlineRenderUnitExecutor
Dział zatytułowany „NextPDF\Pro\Stream\Engine\InlineRenderUnitExecutor”final readonly, __construct(RenderEngineInterface $inner). Renderuje każdą jednostkę po kolei przez wewnętrzny silnik — deterministyczne odniesienie poprawności, które równoległy wykonawca musi dopasować bajt w bajt. Bez czasu, procesów, wątków ani losowości.
NextPDF\Pro\Stream\Engine\ProcessPoolRenderUnitExecutor
Dział zatytułowany „NextPDF\Pro\Stream\Engine\ProcessPoolRenderUnitExecutor”final readonly. Rozdziela partię na maksymalnie maxWorkers podprocesów roboczych php (po jednym fragmencie każdy), które renderują równolegle; wynik jest bajtowo identyczny z punktem odniesienia inline. Konstruktor:
__construct( int $maxWorkers = 4, int $maxBatchSize = 64, ?string $phpBinary = null, ?string $workerScript = null, ?string $autoload = null, ?int $timeoutSeconds = 300, // null disables the wall-clock watchdog)Kontrakt odporności:
- Wolny od zakleszczeń, bezpieczny dla Windows. Ładunki jednostek i wyniki podróżują przez pliki tymczasowe, a nie potoki; rodzic odpytuje
proc_get_status()i opróżnia potok do EOF dopiero po zakończeniu pracownika, więc pracownik nie może zaklinować rodzica. - Ograniczone oczekiwanie.
timeoutSecondsogranicza całe renderowanie równoległe; po wygaśnięciu każdy wciąż działający pracownik jest terminowany i zgłaszany jestRenderEngineException. - Higiena zasobów. Blok
finallyzamyka potoki, podejmuje ograniczoną próbę terminowania i odzyskania (reap) ocalałych pracowników (łagodne terminowanie → wymuszone zabicie → odzyskanie; dziecko, którego nie zaobserwowano jako zatrzymane w ograniczonym czasie łaski, jest porzucane zamiast ryzykować nieokreślone zablokowanie) oraz odlinkowuje każdy plik tymczasowy na wszystkich ścieżkach. - Zaufana korelacja. Każdy pracownik musi zwrócić dokładnie przypisany mu zestaw indeksów (bez brakującego, zduplikowanego ani obcego indeksu); bajty każdego wyrenderowanego wyniku są ponownie hashowane i porównywane z sha-256 zgłoszonym przez pracownika, a każdy status inny niż
rendered/failedtwardo zawodzi. Niepowodzenie renderowania pojedynczego manifestu to wynikFaileddla danej jednostki; tylko usterka infrastrukturalna (niezerowe wyjście, nieczytelny/uszkodzony wynik, timeout) twardo zawodzi wykonawcę.
isAvailable() wymaga istnienia zarówno pliku autoload, jak i skryptu pracownika. Niedodatnie ograniczenie lub ujemny timeout zgłasza InvalidArgumentException.
Jednostki renderowania i wyniki
Dział zatytułowany „Jednostki renderowania i wyniki”NextPDF\Pro\Stream\Engine\RenderUnit
Dział zatytułowany „NextPDF\Pro\Stream\Engine\RenderUnit”final readonly — int<0, max> $index, RenderManifest $manifest, array<string, scalar> $variables. Korelacja odbywa się po index, nigdy po identyfikatorze zadania (identyfikatory zadań nie są gwarantowanie unikalne w obrębie partii).
NextPDF\Pro\Stream\Engine\CompletedRenderUnit
Dział zatytułowany „NextPDF\Pro\Stream\Engine\CompletedRenderUnit”final readonly — int $index (niezaufany, walidowany przez silnik), EngineRenderResult $result.
NextPDF\Pro\Stream\Engine\EngineRenderResult
Dział zatytułowany „NextPDF\Pro\Stream\Engine\EngineRenderResult”final readonly. Pola: jobId, EngineRenderStatus $status, ?string $bytes, ?string $sha256, int $pageCount, ?string $errorCode, ?string $errorMessage, array<non-empty-string, float> $timings. Fabryki: rendered(jobId, bytes, sha256, pageCount, timings = []), failed(jobId, errorCode, errorMessage), timedOut(jobId, errorMessage) (kod SPEC-ENGINE-TIMEOUT). isRendered() raportuje status. Wyrenderowany wynik niesie bajty i skrót, nigdy zatwierdzonej lokalizacji.
NextPDF\Pro\Stream\Engine\EngineRenderStatus
Dział zatytułowany „NextPDF\Pro\Stream\Engine\EngineRenderStatus”Wyliczenie oparte na łańcuchu: Rendered, Failed, Timeout. isRetryable() jest true tylko dla Timeout, więc wywołujący klasyfikuje timeout jako przejściowy bez ponownego badania błędu.
Zatwierdzanie
Dział zatytułowany „Zatwierdzanie”NextPDF\Pro\Stream\Commit\OutputCommitterInterface
Dział zatytułowany „NextPDF\Pro\Stream\Commit\OutputCommitterInterface”public function commit( string $jobId, OutputObjectKey $target, string $bytes, string $sha256, bool $overwrite = false,): CommitReceipt;Publikacja dokładnie raz: atomowa, idempotentna (bajtowo identyczne ponowne zatwierdzenie nie wykonuje żadnego zapisu i zwraca CommitReceipt z idempotentReuse = true — nowe potwierdzenie, a nie oryginalne; jego committedAt to bieżący zegar), bez cichego nadpisywania oraz ze sprawdzeniem integralności (committer przelicza skrót). Tryby awarii: CommitIntegrityException (zadeklarowane sha-256 nie pasuje do bajtów), OutputCommitConflictException (rozbieżne bajty przy zajętym kluczu z overwrite = false), UnsupportedTargetException (nieobsługiwany schemat celu).
NextPDF\Pro\Stream\Commit\LocalFilesystemCommitter
Dział zatytułowany „NextPDF\Pro\Stream\Commit\LocalFilesystemCommitter”final readonly, implementuje OutputCommitterInterface, DurableCapability. __construct(string $rootDirectory, ?AtomicFileWriter $writer = null, ?ClockInterface $clock = null). Obsługuje wyłącznie schemat file; rozwiązuje każdy cel pod jednym skonfigurowanym katalogiem głównym i zapisuje przez atomowy pisarz (O_EXCL temp → fsync → zmiana nazwy w obrębie tego samego woluminu). Cała sekcja krytyczna (w tym tworzenie katalogu nadrzędnego) działa pod wyłącznym flock na pliku blokady dla danego katalogu głównego, trzymanym poza przestrzenią kluczy wyjścia, a zatwierdzenie jest fail-closed, jeśli blokady nie da się otworzyć ani uzyskać. Odmawia obsługi ostatecznych komponentów będących dowiązaniami symbolicznymi oraz każdego klucza zawierającego dwukropek (wektor alternatywnego strumienia danych NTFS). Międzyhostowe dostarczanie dokładnie raz do tego samego klucza współbieżnie wymaga trwałego committera Enterprise. Katalog główny, który jest systemowym katalogiem tymczasowym lub go zawiera, zgłasza InvalidArgumentException.
NextPDF\Pro\Stream\Commit\CommitReceipt
Dział zatytułowany „NextPDF\Pro\Stream\Commit\CommitReceipt”final readonly — jobId, OutputObjectKey $target, sha256, int<0, max> $bytesWritten, bool $idempotentReuse, DateTimeImmutable $committedAt. toArray() / fromArray() są w pełni odwracalne (cel jest ustrukturyzowany, a nie stratnym URI); fromArray() jest ścisłe i zgłasza InvalidArgumentException przy brakujących lub zniekształconych polach.
Punkt kontrolny
Dział zatytułowany „Punkt kontrolny”NextPDF\Pro\Stream\Checkpoint\CheckpointStoreInterface
Dział zatytułowany „NextPDF\Pro\Stream\Checkpoint\CheckpointStoreInterface”load(string $runId): ?RunCheckpoint oraz save(RunCheckpoint $checkpoint): void (trwałe i atomowe — czytelnik nigdy nie widzi połowicznie zapisanego punktu kontrolnego).
NextPDF\Pro\Stream\Checkpoint\RunCheckpoint
Dział zatytułowany „NextPDF\Pro\Stream\Checkpoint\RunCheckpoint”final readonly — runId, int<0, max> $committedOffset, array $keyedState, DateTimeImmutable $updatedAt; SCHEMA_VERSION = '1.0'. Fabryki start(runId, at) oraz advancedTo(committedOffset, keyedState, at). toArray()/toJson()/fromArray()/fromJson() serializują go; fromArray() wymaga niepustego identyfikatora przebiegu i prawidłowego updated_at, odrzuca niezgodne (nie-1.x) schema_version oraz normalizuje stan z kluczami, odrzucając na każdej głębokości wszelkie wartości nieserializowalne do JSON, tak aby odtworzony stan zawsze dało się ponownie zserializować. Przy odtwarzaniu procesor przewija do przodu poza committedOffset i odtwarza stan z kluczami; stan zmutowany po ostatniej barierze jest przeliczany do przodu, nigdy nie jest błędem, ponieważ trwałe dokładnie raz pochodzi z deduplikacji skrótów w committerze.
NextPDF\Pro\Stream\Checkpoint\FilesystemCheckpointStore
Dział zatytułowany „NextPDF\Pro\Stream\Checkpoint\FilesystemCheckpointStore”final readonly, implementuje CheckpointStoreInterface, DurableCapability. Jeden plik JSON na przebieg, zapisywany atomowo. Identyfikatory przebiegów muszą pasować do [A-Za-z0-9._-]+ i nie mogą zawierać ..; nieistniejący katalog zgłasza InvalidArgumentException.
Deduplikacja idempotentności
Dział zatytułowany „Deduplikacja idempotentności”NextPDF\Pro\Stream\Dedup\IdempotencyStoreInterface
Dział zatytułowany „NextPDF\Pro\Stream\Dedup\IdempotencyStoreInterface”isCommitted(IdempotencyKey $key): bool, markCommitted(IdempotencyKey $key, CommitReceipt $receipt): void, receiptFor(IdempotencyKey $key): ?CommitReceipt. Szybka ścieżka, która zwarciowo pomija renderowanie powtórki; porównanie skrótów w committerze pozostaje trwałą gwarancją, więc utracony rekord w najgorszym razie marnuje ponowne renderowanie, które committer zdeduplikuje.
InMemoryIdempotencyStore— zakres pojedynczego przebiegu / testu (tracony przy awarii).FilesystemIdempotencyStore—DurableCapability; jeden atomowy plik JSON na zatwierdzony klucz (zserializowane potwierdzenie), nazwany skrótem wartości klucza. Oznaczenia są idempotentne; współbieżne ponowne oznaczenie ściga się nieszkodliwie na jednym pliku. Nieistniejący katalog zgłaszaInvalidArgumentException.
Ponawianie i dead-letter
Dział zatytułowany „Ponawianie i dead-letter”NextPDF\Pro\Stream\Retry\RetryPolicy
Dział zatytułowany „NextPDF\Pro\Stream\Retry\RetryPolicy”final readonly — positive-int $maxAttempts, positive-int $baseDelayMs, positive-int $maxDelayMs. __construct(int $maxAttempts = 3, int $baseDelayMs = 100, int $maxDelayMs = 30000) z niezmiennikami maxAttempts >= 1 oraz 1 <= baseDelayMs <= maxDelayMs <= 7 days (w przeciwnym razie InvalidArgumentException). Fabryki default() oraz none() (pojedyncza próba). shouldRetry(int $attempt): bool. delayMsForAttempt(int $attempt): int<0, max> to deterministyczne wykładnicze odczekiwanie baseDelayMs * 2^(attempt-1) ograniczone do maxDelayMs (bez wbudowanego jittera; zastosuj go w miejscu wywołania).
NextPDF\Pro\Stream\Retry\DeadLetterStoreInterface
Dział zatytułowany „NextPDF\Pro\Stream\Retry\DeadLetterStoreInterface”add(DeadLetterRecord $record): void, all(): list<DeadLetterRecord>, count(): int<0, max>.
NextPDF\Pro\Stream\Retry\DeadLetterRecord
Dział zatytułowany „NextPDF\Pro\Stream\Retry\DeadLetterRecord”final readonly — jobId, idempotencyKeyValue, positive-int $attempts, lastErrorCode, lastErrorMessage, DateTimeImmutable $failedAt, opcjonalne ?string $runId, opcjonalne int<1, max> $sourceOffset. dedupKey() to runId:sourceOffset, gdy oba są znane, w przeciwnym razie wartość klucza idempotentności. fromArray() parsuje failed_at ściśle jako ATOM (odrzucając wyrażenia względne lub nie-ATOM), więc serializacja/deserializacja pozostaje symetryczna.
InMemoryDeadLetterStore— zakres pojedynczego przebiegu / testu.FilesystemDeadLetterStore—DurableCapability; jeden atomowy plik JSON na rekord, nazwany skrótem SHA-256 klucza deduplikacji (….dlq.json), więc ponowne dodanie tego samego elementu przy wznowieniu jest idempotentne.all()odczytuje rekordy w deterministycznej (posortowanej) kolejności i ujawnia uszkodzony rekord przez zgłoszenie wyjątku;count()to tani zliczanie plików, a nie kontrola poprawności.
Stan z kluczami
Dział zatytułowany „Stan z kluczami”NextPDF\Pro\Stream\State\KeyedStateStoreInterface
Dział zatytułowany „NextPDF\Pro\Stream\State\KeyedStateStoreInterface”has, get, put, remove, clear, a także snapshot(): array oraz restore(array $snapshot): void dla granicy punktu kontrolnego. Wartości muszą być serializowalne do JSON. Dla domyślnego obciążenia render-and-commit żaden stan z kluczami nie jest używany; istnieje on dla rozszerzeń agregacji/okienkowania. InMemoryKeyedStateStore to implementacja pojedynczego przebiegu; jego utrata przy odtwarzaniu jest semantycznie bezskuteczna dla domyślnego obciążenia, ponieważ dokładnie raz pochodzi z deduplikacji skrótów w committerze.
NextPDF\Pro\Stream\State\KeySelector
Dział zatytułowany „NextPDF\Pro\Stream\State\KeySelector”final readonly, __construct(string $tenantField = 'tenant_id', string $documentField = 'document_id'). keyFor(RenderManifest $manifest): non-empty-string wyprowadza klucz partycji z metadanych manifestu jako rawurlencode(tenant):rawurlencode(document) (kodowanie powstrzymuje kolizję ("a:b","c") z ("a","b:c")), z fallbackiem do identyfikatora zadania, gdy któregokolwiek pola brakuje — więc każdy manifest rozwiązuje się do stabilnego, niepustego klucza.
Znacznik trwałości i wyjątki
Dział zatytułowany „Znacznik trwałości i wyjątki”NextPDF\Pro\Stream\DurableCapability to interfejs znacznikowy dla każdego magazynu/committera, którego stan przetrwa restart procesu. Przebieg odporny na awarie wymaga, aby każdy współpracownik go implementował, więc zawodzi szybko, zamiast obiecywać dokładnie raz, którego magazyn w pamięci nie jest w stanie utrzymać.
Wszystkie wyjątki podsystemu implementują NextPDF\Pro\Stream\Exception\StreamException (rozszerza Throwable), więc wywołujący może jednolicie catch (StreamException):
RenderEngineException(RuntimeException) — wykonawca naruszył kontrakt partii (nieznana, zduplikowana lub brakująca jednostka; usterka pracownika; timeout).CommitIntegrityException(RuntimeException) — zadeklarowane sha-256 nie pasuje do ładunku; kod specSPEC-COMMIT-422.OutputCommitConflictException(RuntimeException) — rozbieżne bajty przy zajętym kluczu z wyłączonym nadpisywaniem; kod specSPEC-COMMIT-409(udostępniany przezspecCode()).UnsupportedTargetException(InvalidArgumentException) — schemat celu, którego committer nie potrafi obsłużyć.
Zgodność
Dział zatytułowany „Zgodność”Silnik waliduje manifesty względem modelu manifestu Core i produkuje deterministyczne bajty wraz ze skrótami sha-256; committer egzekwuje atomowe, sprawdzane pod kątem integralności zapisy dokładnie raz. Moduł nie wykonuje żadnych operacji kryptograficznych poza skrótami treści sha-256 i nie definiuje zachowania specyficznego dla FIPS.
Przypadki brzegowe i pułapki
Dział zatytułowany „Przypadki brzegowe i pułapki”renderBatch()nigdy nie przerywa przy niepowodzeniu pojedynczego manifestu; sprawdź każdyEngineRenderResult.ProcessPoolRenderUnitExecutorkoreluje ściśle po indeksie i ponownie hashuje bajty pracownika; wadliwy pracownik twardo zawodzi, zamiast zepsuć wynik.LocalFilesystemCommitterjest jednohostowy; międzyhostowe dokładnie raz wymaga trwałego committera Enterprise.- Przebiegi odporne na awarie muszą wszędzie używać magazynów
DurableCapability(na systemie plików), a nie wariantów w pamięci.
Granica publikacji
Dział zatytułowany „Granica publikacji”Ta strona dokumentuje wyłącznie zachowanie obserwowalne z zewnątrz oraz wspieraną publiczną powierzchnię API. Wewnętrzne ścieżki przestrzeni nazw, klasy pomocnicze, tabele mechanizmów, nazwy plików runbooków i prefiksy zgłoszeń są poza zakresem.