Enterprise 에디션
Stream: 문서 작업 처리
한눈에 보기
섹션 제목: “한눈에 보기”NextPDF\Enterprise\Stream\DocumentJobStreamProcessor는 렌더 매니페스트 스트림을 내구성 있고 책임 추적이 가능한 결과로 전환합니다. 이것은 iterable<RenderManifest>를 제너레이터로 소비하고, Pro 렌더 엔진을 통해 제한된 윈도를 렌더링하며, 모든 작업을 소스 순서로 마무리합니다. 각 작업은 정확히 하나의 종단 상태로 끝납니다: 출력 커밋됨, 이미 커밋된 것으로 인식됨, 또는 데드레터링됨. 진행 상황은 체크포인트로 기록되므로, 크래시된 실행은 어떤 것도 다시 게시하지 않고 재개됩니다.
Stream 이야기는 두 에디션에 걸쳐 나뉘며, 그 분할은 의도적입니다. Pro는 내구성 있고 동시적인 렌더 엔진과 로컬 단일 호스트 파일시스템 저장소를 제공합니다 — 프로세스 내부의 절반입니다. Enterprise는 이 문서 작업 스트림 프로세서에 더해 호스트 경계를 넘는 부분들을 제공합니다: 객체 스토리지 커미터(ObjectStorageCommitter)와 종단 이벤트의 내구성 있는 아웃박스(FilesystemOutboxEmitter). Pro Stream 페이지는 그 쪽에서 동일한 경계를 명시합니다.
가용성 및 라이선싱
섹션 제목: “가용성 및 라이선싱”이 기능은 NextPDF Enterprise(nextpdf/enterprise)에 포함되어 제공되며 Enterprise 등급 라이선스 봉투로 활성화됩니다. 해당 권한이 없는 배포는 이 기능의 클래스를 로드하지 않습니다. 에디션을 비교하고 라이선스를 받으세요.
composer require nextpdf/enterprise이 페이지의 클래스들은 NextPDF\Enterprise\Stream와 NextPDF\Enterprise\Stream\Storage 아래에 있습니다. 이들은 NextPDF\Pro\Stream의 고정된 Pro 계약을 소비합니다 — 엔진, 커미터, 체크포인트, 멱등성, 재시도, 데드레터 인터페이스.
개념 개요
섹션 제목: “개념 개요”프로세서의 임무는 렌더링이 아니라 전달 시맨틱입니다. 이것은 매니페스트 스트림을 엔진의 배치 크기보다 크지 않은 소스 오프셋 윈도로 그룹화합니다. 각 윈도는 RenderEngineInterface::renderBatch()를 통해 렌더링되며, 항목별 타임아웃에 대한 제한적이고 결정적인 재시도를 동반합니다. 그런 다음 모든 항목이 소스 오프셋 순서로 종단 결과로 마무리됩니다.
정확히 한 번 경계는 항목별이며, 조정이 아니라 커미터에 고정되어 있습니다. 내구성 있는 진행 상황은 1 기반 오프셋 하이워터마크입니다: 체크포인트 이하의 모든 오프셋은 종단 결과에 도달했습니다. 배리어 순서는 고정되어 있습니다: 바이트를 커밋하고, 워터마크를 전진시키고, 체크포인트를 저장하고, 버퍼링된 멱등성 마크를 플러시한 다음, 종단 이벤트를 방출합니다. 커밋과 체크포인트 사이의 크래시는 커미터가 다이제스트를 비교하기 때문에 재개 시 멱등적으로 다시 커밋합니다. 체크포인트 이후의 크래시는 오프셋을 지나쳐 빠르게 전진하므로 아무것도 두 번 게시되지 않습니다.
ObjectStorageCommitter는 최소한의 ObjectStorageClientInterface를 통해 객체 저장소에 대해 Pro OutputCommitterInterface를 구현합니다. 타깃의 container는 버킷이고 그 key는 객체 키입니다. 동일한 바이트를 다시 커밋하는 것은 다이제스트가 비교되는 무연산입니다. overwrite 없이 분기하는 바이트는 SPEC-COMMIT-409 충돌을 일으킵니다. 새 객체는 오직 원자적 putIfAbsent() 조건부 쓰기로만 생성됩니다. 그 경쟁에서 지면 제한된 재읽기-및-해결 루프가 트리거됩니다. 따라서 교차 작성자 정확히 한 번은 어댑터의 putIfAbsent()가 진정한 조건부 쓰기인 만큼만 정확히 성립합니다 — S3에서는 If-None-Match: *, GCS에서는 ifGenerationMatch: 0. 이 주기는 인터페이스와 인메모리 NullObjectStorageClient를 함께 제공합니다. 실시간 S3/GCS 어댑터는 호스트에서 제공됩니다.
종단 이벤트는 다운스트림 시스템을 위해 루프를 닫습니다. 체크포인트 배리어 이후 프로세서는 마무리된 각 작업에 대해 JobTerminalEvent를 방출하려고 시도합니다 — 식별자, 상태, 영수증, 오류 세부 정보, 시도 횟수, 그리고 절대 어떤 PDF 바이트도 포함하지 않습니다. 일반 콜백 이미터를 사용하면 방출은 최대 한 번입니다: 체크포인트 이후의 이벤트는 크래시 재개 시 건너뛸 수 있습니다. FilesystemOutboxEmitter는 emit()이 실행되면 모든 이벤트를 내구성 있게 만듭니다: 각 이벤트는 그 결정적 eventId의 해시로 명명된 하나의 원자적 JSON 파일이므로, 재개 후 다시 방출하는 것은 멱등적이고, 릴레이는 최소 한 번 전달하며, 소비자는 eventId로 중복을 제거합니다. 어느 쪽이든 한 가지 경계가 남습니다: 방출은 체크포인트 배리어 이후에 발생하므로, checkpoint.save()와 emit() 사이의 크래시는 재개 시 해당 항목의 종단 이벤트를 건너뜁니다. 완전한 이벤트 원장을 요구하는 다운스트림 시스템은 아웃박스 단독이 아니라 커밋된 객체(저장소가 진실의 원천입니다)에 대해 조정해야 합니다.
라이선싱은 출력 경로에 연결되어 있습니다. withBrandingFromLicense() 팩토리는 실행당 한 번 라이선스로부터 평가 브랜딩 전략을 해결합니다. 유료 라이선스는 항등 변환으로 해결됩니다. 평가 또는 누락된 라이선스는 커밋된 모든 문서에 워터마크를 표시하며, 브랜딩할 수 없는 문서는 데드레터링됩니다 — 프로세서는 브랜딩되지 않은 평가 바이트를 절대 커밋하지 않습니다.
왜 이렇게 작동하는가
섹션 제목: “왜 이렇게 작동하는가”핵심을 지탱하는 결정은 정확히 한 번이 분산 잠금이나 합의가 아니라 커미터의 다이제스트 비교되고 조건부로 생성된 객체에 의존한다는 것입니다. 객체 저장소의 조건부 쓰기는 이 설계가 요구하는 유일한 원자적 기본 요소이며, 그 밖의 모든 것은 실패하고 복구되도록 허용됩니다. 그렇기 때문에 렌더 엔진은 부작용이 없어야 하고, 키가 지정된 상태와 실행 내 중복 제거 캐시는 재계산 가능한 가속으로 취급되며, 모호한 커밋은 추측하는 대신 실행을 중단합니다: 재개 경로는 동일한 다이제스트 비교를 통해 수렴합니다. 또한 그렇기 때문에 runId당 단일 작성자는 강제되는 리스가 아니라 명시된 요구 사항입니다 — 체크포인트 저장소는 의도적으로 단순하게 유지되고, 커밋 계층이 안전망으로 남습니다.
설계 배경: 대용량 문서 생성.
API 표면
섹션 제목: “API 표면”DocumentJobStreamProcessor
섹션 제목: “DocumentJobStreamProcessor”호스트는 팩토리를 통해 생성해야 라이선스-대-브랜딩 제어가 연결되지 않은 채로 남지 않습니다:
public static function withBrandingFromLicense( RenderEngineInterface $engine, OutputCommitterInterface $committer, IdempotencyStoreInterface $idempotency, CheckpointStoreInterface $checkpoints, KeyedStateStoreInterface $state, DeadLetterStoreInterface $deadLetters, RetryPolicy $retryPolicy, ClockInterface $clock, EntitlementEvaluator $entitlementEvaluator, ?LicenseKey $license, ?StreamProcessorProbe $probe = null, ?JobCompletionEmitterInterface $emitter = null, ?BrandingApplicator $brandingApplicator = null,): self$clock는 Symfony\Component\Clock\ClockInterface입니다(재시도 백오프가 이를 통해 잠듭니다). null 라이선스는 실패 시 닫힘으로 평가 브랜딩으로 해결됩니다.
단일 진입점은 하나의 실행을 처리하고 그 카운터를 반환합니다:
public function process(iterable $manifests, StreamProcessorConfig $config): ProcessingSummary던지거나 실패하는 경우: 크래시 안전 전제 조건이 실패할 때(비내구성 협력자를 사용한 crashSafe 실행) 또는 커밋이 모호할 때 NextPDF\Enterprise\Stream\Exception\StreamProcessorException; windowSize가 엔진의 maxBatchSize()를 초과할 때 InvalidArgumentException.
StreamProcessorConfig
섹션 제목: “StreamProcessorConfig”public function __construct( public string $runId, int $windowSize = 32, int $checkpointIntervalJobs = 100, public bool $crashSafe = true, public bool $emitSkippedCompletions = false,)던지거나 실패하는 경우: windowSize 또는 checkpointIntervalJobs가 1 미만일 때 InvalidArgumentException. $runId는 체크포인트 재개의 키가 되는 안정적인 단일 작성자 실행 식별자입니다.
ObjectStorageCommitter
섹션 제목: “ObjectStorageCommitter”public function __construct( private ObjectStorageClientInterface $client, private string $scheme, private ClockInterface $clock,) {}$scheme는 이 커미터가 서비스하는 타깃 스킴의 이름을 지정합니다(예: s3 또는 gcs); 여기서 $clock는 Psr\Clock\ClockInterface입니다.
public function commit( string $jobId, OutputObjectKey $target, string $bytes, string $sha256, bool $overwrite = false,): CommitReceipt던지거나 실패하는 경우: 스킴 불일치 시 UnsupportedTargetException; 타깃 키가 컨테이너 상대적으로 안전하지 않을 때 RenderManifestException; 선언된 sha-256이 바이트와 일치하지 않을 때 CommitIntegrityException; overwrite 없이 분기하는 바이트에 대해 OutputCommitConflictException(SPEC-COMMIT-409); 동시 변형 하에서 5회 시도 후에도 생성 경쟁이 수렴할 수 없을 때 RuntimeException.
ObjectStorageClientInterface
섹션 제목: “ObjectStorageClientInterface”실시간 S3/GCS 통합이 구현하는 최소 어댑터 표면:
public function shaOf(string $bucket, string $key): ?string;
public function put(string $bucket, string $key, string $bytes, string $sha256): void;
public function putIfAbsent(string $bucket, string $key, string $bytes, string $sha256): bool;putIfAbsent()는 실제 원자적 조건부 생성이어야 하며(S3에서는 If-None-Match: *, GCS에서는 ifGenerationMatch: 0), 이 호출이 객체를 썼을 때만 true를 반환합니다. put()은 매니페스트가 overwrite를 요청했을 때만 사용되는 무조건적 덮어쓰기입니다.
JobCompletionEmitterInterface와 FilesystemOutboxEmitter
섹션 제목: “JobCompletionEmitterInterface와 FilesystemOutboxEmitter”public function emit(JobTerminalEvent $event): void;이미터는 프로세서에서 선택 사항입니다. 이벤트는 항목이 내구성 있게 마무리된 후에만 발동합니다. FilesystemOutboxEmitter는 제공되는 내구성 있는 구현입니다:
public function __construct(string $directory, ?AtomicFileWriter $writer = null)던지거나 실패하는 경우: 디렉터리가 존재하지 않을 때 InvalidArgumentException; 이벤트를 JSON으로 인코딩할 수 없으면 emit()이 RuntimeException을 던집니다. hasEvent(string $eventId): bool은 아웃박스를 확인합니다; count(): int는 전달되지 않은 이벤트를 보고합니다.
JobTerminalEvent와 JobTerminalStatus
섹션 제목: “JobTerminalEvent와 JobTerminalStatus”public function __construct( public string $eventId, public string $runId, public int $sourceOffset, public string $jobId, public string $idempotencyKeyValue, public JobTerminalStatus $status, public ?CommitReceipt $receipt, public ?string $errorCode, public ?string $errorMessage, public int $attempts, public DateTimeImmutable $occurredAt,) {}eventId는 결정적입니다 — runId:sourceOffset:idempotencyKey:status — 이것이 아웃박스 중복 제거를 가능하게 만드는 것입니다. toArray()는 전송을 위해 이벤트를 직렬화합니다; 이것은 어떤 PDF 바이트도 담지 않습니다. JobTerminalStatus는 문자열 enum입니다: Committed(committed), DeadLettered(dead_lettered), Skipped(skipped).
ProcessingSummary
섹션 제목: “ProcessingSummary”process()가 반환하는 불변 카운터: runId, sourceRead, fastForwardedByCheckpoint, skippedByIdempotency, windows, renderBatchCalls, renderRetries, commitReceipts, deadLettered, checkpointSaves, 그리고 finalCommittedOffset(최종 종단 하이워터마크).
코드 샘플 — 빠른 시작
섹션 제목: “코드 샘플 — 빠른 시작”정확히 한 번 객체 스토리지 커밋을 격리해서 보여줍니다. 인메모리 NullObjectStorageClient가 당신의 S3/GCS 어댑터를 대신합니다; 당신이 관찰하는 시맨틱은 실시간 어댑터가 반드시 보존해야 하는 것입니다.
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Stream\Storage\NullObjectStorageClient;use NextPDF\Enterprise\Stream\Storage\ObjectStorageCommitter;use NextPDF\Manifest\OutputObjectKey;use NextPDF\Pro\Stream\Exception\OutputCommitConflictException;use Symfony\Component\Clock\NativeClock;
$committer = new ObjectStorageCommitter( client: new NullObjectStorageClient(), // swap in your S3/GCS adapter scheme: 's3', clock: new NativeClock(),);
$target = new OutputObjectKey(scheme: 's3', container: 'invoices', key: '2026/07/inv-1001.pdf');$bytes = '%PDF-1.7 example-rendered-bytes';$sha = hash('sha256', $bytes);
$first = $committer->commit('inv-1001', $target, $bytes, $sha);$replay = $committer->commit('inv-1001', $target, $bytes, $sha); // crash-resume replay
printf("first : reuse=%s, %d bytes\n", var_export($first->idempotentReuse, true), $first->bytesWritten);printf("replay: reuse=%s\n", var_export($replay->idempotentReuse, true));
try { $divergent = '%PDF-1.7 different-bytes'; $committer->commit('inv-1001', $target, $divergent, hash('sha256', $divergent));} catch (OutputCommitConflictException $conflict) { echo 'conflict: ' . $conflict->specCode() . "\n"; // no silent clobber}예상 출력:
first : reuse=false, 31 bytesreplay: reuse=trueconflict: SPEC-COMMIT-409코드 샘플 — 프로덕션
섹션 제목: “코드 샘플 — 프로덕션”완전한 크래시 안전 실행: 내구성 있는 Pro 저장소, 객체 스토리지 커미터, 내구성 있는 아웃박스, 그리고 라이선스로 해결된 브랜딩. 크래시 후 동일한 runId를 다시 실행하면 빠르게 전진하고 수렴합니다.
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Licensing\EntitlementEvaluator;use NextPDF\Enterprise\Stream\DocumentJobStreamProcessor;use NextPDF\Enterprise\Stream\Exception\StreamProcessorException;use NextPDF\Enterprise\Stream\FilesystemOutboxEmitter;use NextPDF\Enterprise\Stream\Storage\ObjectStorageCommitter;use NextPDF\Enterprise\Stream\StreamProcessorConfig;use NextPDF\Manifest\Render\SingleDocumentRenderer;use NextPDF\Manifest\RenderManifest;use NextPDF\Pro\Stream\Checkpoint\FilesystemCheckpointStore;use NextPDF\Pro\Stream\Dedup\FilesystemIdempotencyStore;use NextPDF\Pro\Stream\Engine\InProcessRenderEngine;use NextPDF\Pro\Stream\Retry\FilesystemDeadLetterStore;use NextPDF\Pro\Stream\Retry\RetryPolicy;use NextPDF\Pro\Stream\State\InMemoryKeyedStateStore;use Symfony\Component\Clock\NativeClock;
// Production requires a host-supplied adapter whose putIfAbsent() is a TRUE// atomic conditional create (S3 If-None-Match: *, GCS ifGenerationMatch: 0)// and whose shaOf() reads durable object state. NullObjectStorageClient is// for the quick start only - it keeps nothing across processes.$s3Client = new \Aws\S3\S3Client(['region' => 'eu-central-1', 'version' => 'latest']);$objectClient = new \Acme\Storage\S3ObjectStorageClient($s3Client); // implements ObjectStorageClientInterface
$stateDir = '/var/lib/nextpdf/stream';foreach (['checkpoints', 'idempotency', 'dead-letters', 'outbox'] as $sub) { if (!is_dir($stateDir . '/' . $sub)) { mkdir($stateDir . '/' . $sub, 0770, true); }}
// One manifest per JSONL line; the generator never materialises the batch.$manifests = (static function (string $path): Generator { $handle = fopen($path, 'rb'); if ($handle === false) { throw new RuntimeException('Cannot open job stream: ' . $path); } try { while (($line = fgets($handle)) !== false) { if (trim($line) !== '') { yield RenderManifest::fromJson(trim($line)); } } } finally { fclose($handle); }})('/var/spool/nextpdf/jobs.jsonl');
$license = null; // your licensing bootstrap yields a LicenseKey; null = evaluation branding
$processor = DocumentJobStreamProcessor::withBrandingFromLicense( engine: new InProcessRenderEngine(SingleDocumentRenderer::standalone()), // For a live bucket, implement ObjectStorageClientInterface over your S3/GCS SDK. committer: new ObjectStorageCommitter($objectClient, 's3', new NativeClock()), idempotency: new FilesystemIdempotencyStore($stateDir . '/idempotency'), checkpoints: new FilesystemCheckpointStore($stateDir . '/checkpoints'), state: new InMemoryKeyedStateStore(), // recomputable; durability not required here deadLetters: new FilesystemDeadLetterStore($stateDir . '/dead-letters'), retryPolicy: new RetryPolicy(maxAttempts: 3, baseDelayMs: 200, maxDelayMs: 5_000), clock: new NativeClock(), entitlementEvaluator: new EntitlementEvaluator(), license: $license, emitter: new FilesystemOutboxEmitter($stateDir . '/outbox'),);
$config = new StreamProcessorConfig( runId: 'nightly-invoices-2026-07-03', windowSize: 32, checkpointIntervalJobs: 100, crashSafe: true,);
try { $summary = $processor->process($manifests, $config);} catch (StreamProcessorException $e) { // Ambiguous commit or a non-durable collaborator: the finalized prefix is // checkpointed. Re-run the SAME runId; the committer converges by digest. fwrite(STDERR, 'Run aborted for safe resume: ' . $e->getMessage() . PHP_EOL); exit(1);}
printf( "run %s: read=%d committed=%d dedup-skipped=%d dead-lettered=%d checkpoints=%d final-offset=%d\n", $summary->runId, $summary->sourceRead, $summary->commitReceipts, $summary->skippedByIdempotency, $summary->deadLettered, $summary->checkpointSaves, $summary->finalCommittedOffset,);예시 출력(카운터는 당신의 작업 스트림에 따라 달라집니다):
run nightly-invoices-2026-07-03: read=1200 committed=1187 dedup-skipped=13 dead-lettered=0 checkpoints=12 final-offset=1200엣지 케이스 및 주의점
섹션 제목: “엣지 케이스 및 주의점”runId당 단일 작성자는 당신의 책임입니다. 체크포인트 저장소에는 리스나 비교-후-교체가 없습니다. 하나의runId에 대한 두 개의 동시 작성자는 계약 밖에 있습니다; 스케줄러에서 배타성을 강제하세요.crashSafe: true는 비내구성 협력자에 대해 빠르게 실패합니다. 커미터, 체크포인트, 멱등성, 데드레터 저장소는 모두DurableCapability마커를 구현해야 하며, 그렇지 않으면process()가 위반자를 지목하는StreamProcessorException을 던집니다. 키가 지정된 상태 저장소는 의도적으로 면제됩니다: 손실된 키 상태는 체크포인트 이후로부터 재계산됩니다.windowSize는 엔진에 맞아야 합니다.maxBatchSize()보다 큰 윈도는 어떤 작업이 시작되기 전에InvalidArgumentException을 던집니다.- 모호한 커밋은 중단합니다; 충돌은 그렇지 않습니다.
SPEC-COMMIT-409는 결정적 종단 충돌입니다: 해당 항목은 데드레터링되고 실행은 계속됩니다. 그 밖의 모든 커밋 실패는 모호합니다: 마무리된 접두부가 체크포인트되고 실행은 안전한 재개를 위해 던집니다. - 렌더 실패는 절대 실행을 중단하지 않습니다. 항목별
Failed결과, 소진된 재시도 예산, 또는 브랜딩할 수 없는 평가 바이트는 모두 해당 항목을 데드레터링하고 계속합니다. - 중복
jobId값은 안전합니다; 중복 작업은idempotencyKey를 기준으로 처리됩니다. 결과는jobId가 아니라 고유한 소스 오프셋으로 항목과 상관관계를 맺습니다. 중복 멱등성 키는 재렌더링 전에, 동일한 배리어 간격 내에서도 인식됩니다. - 이미터 내구성이 이벤트 시맨틱을 결정합니다. 일반 콜백 이미터는 관찰자 전용이며 크래시에 걸쳐 최대 한 번입니다.
FilesystemOutboxEmitter는 아웃박스를 내구성 있고 중복 제거 키가 지정되게 만듭니다; 그러면 릴레이 전달은 최소 한 번이며, 다운스트림 정확히 한 번은eventId에 대한 소비자 중복 제거를 요구합니다. 그것의 디렉터리는(모든 파일시스템 저장소와 마찬가지로) 미리 존재해야 하며, 그렇지 않으면 생성자가InvalidArgumentException을 던집니다. - 건너뛴 이벤트는 기본적으로 꺼져 있습니다. 중복 제거로 단락된 항목에 대해서도
Skipped종단 이벤트를 방출하려면emitSkippedCompletions: true를 설정하세요.
보안 참고사항
섹션 제목: “보안 참고사항”- 출력 키는 실패 시 닫힙니다.
commit()은 타깃 키가 컨테이너 상대적으로 안전한지 다시 확인합니다:..순회 없음, 절대 경로 탈출 없음, 널 바이트 없음, 내장된 스트림 래퍼 스킴 없음, 그리고 콜론 없음(NTFS 대체 데이터 스트림 벡터를 닫음). 안전하지 않은 키는 어떤 스토리지 호출 전에 던집니다. - 무결성은 경계에서 재검증됩니다. 커미터는 실제 바이트에 대해 sha-256을 재계산하고 불일치를
CommitIntegrityException으로 거부하므로, 손상된 인계는 조용히 안착할 수 없습니다. - 이벤트는 어떤 문서 내용도 담지 않습니다.
JobTerminalEvent와 아웃박스 행은 식별자, 다이제스트, 타임스탬프, 오류 문자열만 보유합니다. 오류 메시지는 엔진 진단을 반영할 수 있습니다; 아웃박스 파일을 서드파티 싱크로 보내기 전에 그것들과 테넌트를 식별하는 모든jobId스킴을 정리하세요. - 평가 출력은 절대 브랜딩되지 않은 채로 게시되지 않습니다. 브랜딩이 요구되지만 적용될 수 없을 때, 해당 항목은 커밋되는 대신 데드레터링됩니다.
- 교차 작성자 정확히 한 번은 당신의 어댑터만큼만 강력합니다.
putIfAbsent()가 진정한 원자적 조건부 쓰기가 아니라면, 보장은 단일 작성자 시맨틱으로 저하됩니다. 객체 저장소 자격 증명과 버킷 정책은 호스트의 관심사입니다; 모듈은 그것들을 절대 관리하지 않습니다.
적합성
섹션 제목: “적합성”이 모듈의 동작을 정의하는 발행된 표준은 없습니다. 이 페이지의 정확히 한 번, 체크포인트, 아웃박스 보장은 NextPDF Enterprise API의 엔지니어링 계약이며, 여기서 외부에서 관찰 가능한 동작으로 명시됩니다 — 이것들은 어떤 표준에 대한 적합성이나 인증이 아닙니다. 무결성 다이제스트로서의 SHA-256의 내부 사용도 마찬가지로 배관이며, 규정 준수 주장이 아닙니다. NextPDF의 모든 곳에서와 같이: 지원은 적합성이 아니며, 적합성은 인증이 아닙니다. NextPDF는 어떤 인증도 보유하지 않으며 어떤 것도 부여하지 않습니다; 이 모듈을 기반으로 구축된 배포가 당신의 규제 또는 계약상 의무를 충족하는지는 당신의 평가자가 내릴 판단입니다.
동작 계약
섹션 제목: “동작 계약”종단 이벤트는 체크포인트 트랜잭션의 일부가 아닙니다: 방출은 checkpoint.save() 이후에 실행되므로, 아웃박스는 모든 방출된 이벤트를 내구성 있게 보유하지만 크래시에 걸쳐 완전한 원장은 아닙니다. 커밋된 객체가 진실의 원천으로 남습니다.
finalCommittedOffset이하의 모든 소스 오프셋은 정확히 하나의 종단 결과에 도달했습니다:Committed,Skipped, 또는DeadLettered.- 항목은 소스 오프셋 순서로 마무리됩니다; 배리어 순서는 커밋, 체크포인트 저장, 멱등성 마크 플러시, 그다음 이벤트 방출입니다.
- 동일한
runId로 실행을 다시 실행하는 것은 절대 이중 게시하지 않습니다: 체크포인트된 오프셋은 빠르게 전진하고, 바이트가 동일한 재커밋은idempotentReuse: true로 다이제스트가 비교되는 무연산입니다. - 새 객체는 오직 원자적 조건부 생성을 통해서만 생성됩니다;
overwrite없이 점유된 키에서 분기하는 바이트는 클로버가 아니라 결정적SPEC-COMMIT-409데드레터입니다. - 모호한 커밋은 마무리된 접두부를 체크포인트하고
StreamProcessorException으로 중단합니다; 실패한 오프셋은 전진되지 않습니다. crashSafe실행은 어떤 입력을 읽기 전에 비내구성 커미터, 체크포인트, 멱등성, 또는 데드레터 협력자를 거부합니다.- 이벤트 id는 실행, 오프셋, 멱등성 키, 상태의 순수 함수이므로, 내구성 있는 아웃박스는 이벤트당 최대 한 행을 보유합니다.
Core 폴백
섹션 제목: “Core 폴백”NextPDF Core는 라이터와 렌더-매니페스트 계약을 통해 한 번에 한 문서를 렌더링합니다 — Writer를 참조하세요. Core 단독으로는 내구성 있는 작업 스트림도, 체크포인트 재개도, 멱등성 중복 제거도, 객체 스토리지 커밋도, 종단 이벤트 아웃박스도 없습니다. NextPDF Pro는 내구성 있고 동시적인 렌더 엔진과 단일 호스트 파일시스템 저장소를 추가합니다(Pro의 Stream). 교차 호스트 절반 — 이 프로세서, 객체 스토리지 커미터, 내구성 있는 아웃박스 — 는 NextPDF Enterprise를 요구합니다.
발행 경계
섹션 제목: “발행 경계”이 페이지는 외부에서 관찰 가능한 동작과 지원되는 공개 API 표면만 문서화합니다. 내부 네임스페이스 경로, 헬퍼 클래스, 메커니즘 표, 런북 파일명, 티켓 접두사는 범위 밖입니다.
함께 보기
섹션 제목: “함께 보기”- Stream (Pro) — 프로세스 내부 절반: 렌더 엔진, 실행기, 로컬 내구성 저장소.
- Stream — 심층 레퍼런스 — 공유 Stream 인터페이스에 대한 계약 수준 레퍼런스.
- 출력 파이프라인 (Enterprise) — 파이프라인 매니페스트에 대한 배치 오케스트레이션.
- 평가판 및 브랜딩 — 평가 브랜딩이 어떻게 해결되고 적용되는지.
- 대용량 문서 생성 — 이 모듈이 존재하는 시나리오.
- 프로덕션에서 NextPDF 운영하기 — 장기 실행 워커를 위한 배포 자세.