İçeriğe geç
getnextpdf.com

Pro sürüm

Stream

Stream modülü, belge gruplarını dayanıklı ve eşzamanlı biçimde, tek ana makineli dayanıklı depolara tam olarak bir kez yerel işleme ile oluşturur (çapraz ana makine tam-bir-kez, Enterprise Stream sınırıdır). İşi, temiz biçimde ayrılmış iki sorumluluğa böler: doğrulanmış bildirimleri baytlara (ve başka hiçbir şeye) dönüştüren bir oluşturma motoru ve bu baytları güvenle yayımlayan, bir çökmeden sonra işlenmiş çıktıyı yeniden yayımlamadan bir çalıştırmanın sürmesine izin veren bir dizi dayanıklı depo — işleyici, denetim noktası, idempotency, ölü-mektup.

Bu yetenek NextPDF Pro (nextpdf/pro) ile birlikte gelir ve bir Pro katmanı lisans zarfıyla etkinleşir. Bu yetkiye sahip olmayan bir dağıtım, yeteneğin sınıflarını yüklemez. Sürümleri karşılaştırın ve bir lisans edinin.

Ayrı bir özellik başına lisans bayrağı yoktur. Eşzamanlılık (çalışan sayısı), grup boyutu, yeniden deneme bütçesi ve depo arka ucu (bellek-içi karşısında dayanıklı dosya sistemi), birer lisans anahtarı değil, çalışma zamanı parametreleridir.

Terminal window
composer require nextpdf/pro:^3

Kod, NextPDF\Pro\Stream ad alanı altında yer alır.

Stream, üretim hızı motorunu akış anlam bilgisinden ayıran dondurulmuş bir bağlantı yüzeyi — NextPDF\Pro\Stream\Engine\RenderEngineInterface — çevresinde düzenlenmiştir:

  • Oluşturma motoru, eşzamanlılığı ve sınırlı belleği sahiplenir. Önceden doğrulanmış, önceden yineleme kaldırılmış bir bildirim penceresini renderBatch() aracılığıyla oluşturur ve girdi sırasında her bildirim için bir EngineRenderResult döndürür. Çok önemli olarak, motor nihai çıktıya göre yan etkisizdir: oluşturulmuş baytları ve bunların sha-256 özetini döndürür, asla nihai bir nesne anahtarına yazmaz. Tam olarak bir kez teslimi mümkün kılan, işte bu saflıktır.
  • Akış iş birlikçileri, teslimi sahiplenir. İşleyici, denetim noktası deposu, idempotency (yineleme kaldırma) deposu ve ölü-mektup deposu; baytların nereye ineceğine, bir çalıştırmanın nasıl süreceğine, hangi işin bir yeniden yürütme olduğuna ve nihai başarısızlıklara ne olacağına karar verir.

Bildirim başına bir oluşturma başarısızlığı, öğe başına bir Failed (veya Timeout) sonucu olarak bildirilir; grubu asla durdurmaz. Grup zarfı, öğe başına sonuçlarla her zaman başarılı olur.

  • InProcessRenderEngine, senkron, tek süreçli doğruluk taban çizgisidir. Her bildirimi, onu Core SingleDocumentRenderer aracılığıyla oluşturmadan önce, birlikte gelen RenderManifestValidator üzerinden başarısızlığa kapanır biçimde doğrular; böylece bozuk bir bildirim, oluşturucuya ulaşmak yerine öğe başına bir başarısızlık (hata kodu SPEC-MANIFEST-INVALID) hâline gelir.
  • ConcurrentRenderEngine, bir grubu bir RenderUnitExecutorInterface üzerine yelpazeler ve birim dizinine göre deterministik grup sırasını geri yükler. Çıktı, tamamlanma sırasından bağımsız olarak sıralı bir oluşturmayla bayt-bayt aynıdır; eksik, yinelenen veya bilinmeyen bir tamamlanma sessizce düşürme değil, sert bir başarısızlıktır.
  • Yürütücüler, eşzamanlılık bağlantı yüzeyidir. InlineRenderUnitExecutor, deterministik taban çizgisidir; ProcessPoolRenderUnitExecutor, bir grubu paralel olarak oluşturan en fazla N php çalışan alt sürecine dağıtır, ardından sonuçlarını toplar ve bütünlük denetiminden geçirir.

OutputCommitterInterface::commit(), oluşturulmuş baytları nihai hedeflerine tam olarak bir kez yayımlar: atomik olarak (hiçbir zaman kısmi bir nesne gözlemlenmez), idempotent olarak (bayt-bayt aynı içeriği yeniden işlemek hiçbir yazma gerçekleştirmez ve idempotentReuse = true ile bir CommitReceipt döndürür — orijinali değil, yeni bir makbuz), sessiz ezme olmadan (dolu bir anahtara overwrite olmadan ayrışan baytlar bir çatışma yükseltir) ve bütünlük denetiminden geçirilmiş olarak (işleyici, yazmadan önce özeti yeniden hesaplar). LocalFilesystemCommitter, bunu yerel dosya sistemi için uygular.

Bir RunCheckpoint, bir çalıştırmanın kaç öğe işlediğini ve anahtarlı durumun bir anlık görüntüsünü kaydeden dayanıklı bir engeldir. Kurtarmada işlemci, işlenmiş kaymanın ötesine hızlı ileri sarar ve anahtarlı durumu geri yükler; böylece çalıştırma ortasındaki bir çökme, işlenmiş çıktıyı yeniden yayımlamadan sürer. FilesystemCheckpointStore, her engeli atomik olarak kalıcılaştırır.

Idempotency yineleme kaldırma, yeniden deneme ve ölü-mektuplar

“Idempotency yineleme kaldırma, yeniden deneme ve ölü-mektuplar” başlıklı bölüm

Idempotency deposu, işlemcinin yeniden yürütülen bir bildirimi oluşturmadan önce kısa devre yapmasına izin veren hızlı yoldur; işleyicinin özet karşılaştırması, dayanıklı tam-bir-kez güvencesi olarak kalır; böylece kaybedilen bir yineleme kaldırma kaydı en kötü durumda, işleyicinin yineleme kaldırdığı boşa giden bir yeniden oluşturmaya yol açar. RetryPolicy, uçucu (zaman aşımı) başarısızlıkları için sınırlı, deterministik üstel geri çekilme sağlar; bütçesini tüketen bir iş, kaybedilmek yerine bir DeadLetterStoreInterface içinde yakalanır. Her depo, bir bellek-içi türev (tek çalıştırma / test kapsamı) ile bir dayanıklı dosya sistemi türevi sunar.

Durumu bir süreç yeniden başlatmasından sağ çıkan depolar, DurableCapability işaretçisini uygular. Çökmeye dayanıklı bir çalıştırma, her iş birlikçinin dayanıklı olmasını gerektirir; böylece, bellek-içi bir deponun bir yeniden başlatma boyunca koruyamayacağı tam-bir-kez anlam bilgisini vaat etmek yerine hızlıca başarısız olur.

Bir bildirim oluşturun ve baytlarını tam olarak bir kez işleyin. Motor, baytları ve bir özeti döndürür; işleyici, bunları yayımlar.

stream-quickstart.php
<?php
declare(strict_types=1);
use NextPDF\Manifest\OutputObjectKey;
use NextPDF\Manifest\Render\SingleDocumentRenderer;
use NextPDF\Manifest\RenderManifestBuilder;
use NextPDF\Manifest\TemplateRef;
use NextPDF\Pro\Stream\Commit\LocalFilesystemCommitter;
use NextPDF\Pro\Stream\Engine\InProcessRenderEngine;
$outputRoot = __DIR__ . '/out';
\is_dir($outputRoot) || \mkdir($outputRoot, 0o775, true);
// The engine renders bytes only — it never writes the final object.
$engine = new InProcessRenderEngine(SingleDocumentRenderer::standalone());
$target = OutputObjectKey::file('out', 'invoices/1001.pdf');
$manifest = RenderManifestBuilder::create('invoice-1001')
->withInlineInput('<h1>Invoice 1001</h1><p>Amount due: 42.00</p>')
->withTemplate(TemplateRef::html())
->withOutputKey($target)
->build();
$result = $engine->renderBatch([$manifest])[0];
// A durable committer publishes the rendered bytes exactly once.
$committer = new LocalFilesystemCommitter($outputRoot);
if ($result->isRendered()) {
$receipt = $committer->commit($result->jobId, $target, $result->bytes, $result->sha256);
echo $receipt->target->toUri(), ' (', $receipt->bytesWritten, " bytes)\n";
}

Bir grup oluşturun, zaman aşımlarını yeniden deneme ilkesine yönlendirin ve nihai başarısızlıkları ölü-mektuba gönderin. İşleme, ayrışan baytları ezmeyi reddeder; böylece bir anahtar çakışması, kaybedilmek yerine yakalanır ve tutulur.

stream-production.php
<?php
declare(strict_types=1);
use DateTimeImmutable;
use NextPDF\Manifest\OutputObjectKey;
use NextPDF\Manifest\Render\SingleDocumentRenderer;
use NextPDF\Manifest\RenderManifest;
use NextPDF\Manifest\RenderManifestBuilder;
use NextPDF\Manifest\TemplateRef;
use NextPDF\Pro\Stream\Commit\LocalFilesystemCommitter;
use NextPDF\Pro\Stream\Engine\EngineRenderStatus;
use NextPDF\Pro\Stream\Engine\InProcessRenderEngine;
use NextPDF\Pro\Stream\Exception\OutputCommitConflictException;
use NextPDF\Pro\Stream\Retry\DeadLetterRecord;
use NextPDF\Pro\Stream\Retry\InMemoryDeadLetterStore;
use NextPDF\Pro\Stream\Retry\RetryPolicy;
$outputRoot = __DIR__ . '/out';
\is_dir($outputRoot) || \mkdir($outputRoot, 0o775, true);
$engine = new InProcessRenderEngine(SingleDocumentRenderer::standalone(), maxBatchSize: 64);
$committer = new LocalFilesystemCommitter($outputRoot);
$deadLetter = new InMemoryDeadLetterStore();
$retry = RetryPolicy::default(); // 3 attempts, 100ms base, 30s cap.
/**
* Build one manifest and remember its output target for the commit stage.
*
* @return array{RenderManifest, OutputObjectKey}
*/
$makeJob = static function (string $jobId, string $html): array {
$target = OutputObjectKey::file('out', 'invoices/' . $jobId . '.pdf');
$manifest = RenderManifestBuilder::create($jobId)
->withInlineInput($html)
->withTemplate(TemplateRef::html())
->withOutputKey($target)
->build();
return [$manifest, $target];
};
/** @var array<non-empty-string, OutputObjectKey> $targets */
$targets = [];
$manifests = [];
foreach (['inv-2001' => '<h1>2001</h1>', 'inv-2002' => '<h1>2002</h1>'] as $id => $html) {
[$manifest, $target] = $makeJob($id, $html);
$manifests[] = $manifest;
$targets[$id] = $target;
}
foreach ($engine->renderBatch($manifests) as $result) {
// A timeout is transient — the policy decides whether to re-enqueue it.
if ($result->status === EngineRenderStatus::Timeout && $retry->shouldRetry(1)) {
// Re-enqueue on the caller's work queue after delayMsForAttempt(1) ms.
continue;
}
if (!$result->isRendered()) {
$deadLetter->add(new DeadLetterRecord(
jobId: $result->jobId,
idempotencyKeyValue: $result->jobId,
attempts: $retry->maxAttempts,
lastErrorCode: $result->errorCode ?? 'SPEC-RENDER-EXCEPTION',
lastErrorMessage: $result->errorMessage ?? '',
failedAt: new DateTimeImmutable(),
));
continue;
}
try {
// overwrite=false: identical bytes are an idempotent no-op; divergent
// bytes to an occupied key raise SPEC-COMMIT-409 instead of clobbering.
$receipt = $committer->commit(
$result->jobId,
$targets[$result->jobId],
$result->bytes,
$result->sha256,
);
} catch (OutputCommitConflictException $e) {
$deadLetter->add(new DeadLetterRecord(
jobId: $result->jobId,
idempotencyKeyValue: $result->jobId,
attempts: 1,
lastErrorCode: $e->specCode(),
lastErrorMessage: $e->getMessage(),
failedAt: new DateTimeImmutable(),
));
continue;
}
echo $receipt->idempotentReuse
? "reused {$receipt->target->toUri()}\n"
: "committed {$receipt->target->toUri()}\n";
}
if ($deadLetter->count() > 0) {
\fwrite(\STDERR, $deadLetter->count() . " job(s) dead-lettered\n");
}
  • Üretim hızının eşzamanlı (süreç havuzu) yürütmeden fayda gördüğü yüksek hacimli toplu oluşturma.
  • Bir çökmeden sağ çıkması ve çıktıyı iki kez yayımlamadan sürmesi gereken uzun süreli çalıştırmalar.
  • Oluşturulan her belgenin hedefine tam olarak bir kez teslimini garanti etmesi gereken işlem hatları.

Tek bir özel belge için doğrudan Writer modülüyle oluşturun; Stream’in değeri, dayanıklı, sürdürülebilir, eşzamanlı gruplardadır.

Üretim hızı, ProcessPoolRenderUnitExecutor içinde çalışan sayısıyla ölçeklenir (maxWorkers ve maxBatchSize ile sınırlı), motor ise oluşturma çıktısını sıralı taban çizgisiyle bayt-bayt aynı tutar. Bir duvar saati zaman aşımı, her paralel grubu sınırlar; böylece takılan bir çalışan sonsuza dek engelleyemez. Yayımlanmış sabit bir üretim hızı değeri yoktur; belge karmaşıklığına ve ana makine paralelliğine bağlıdır. Temsili belgelerle ölçün.

Bildirimler, oluşturmadan önce başarısızlığa kapanır biçimde doğrulanır. İşleyici; yol geçişini, boş baytları, akış sarmalayıcı şemalarını, sembolik bağlantılı hedefleri ve NTFS alternatif veri akışı (iki nokta) vektörlerini reddeder ve her anahtarı yapılandırılmış tek bir kök altında çözer. Süreçler arası çalışan sonuçları yeniden karma değerine sokulur ve çalışanın bildirdiği özetle eşleştirilir; böylece bozulmuş bir çalışan çıktıyı sessizce bozamaz. Bu modül hiçbir belge içeriğini günlüğe kaydetmez.

Buradaki Stream dayanıklı depoları, dosya sistemi destekli ve tek ana makinelidir. Aynı anahtara çapraz ana makine eşzamanlı tam-bir-kez ve çalıştırmalar arasında dayanıklı yineleme kaldırma, Enterprise nesne depolama işleyicilerinin ve depolarının işidir; bu iş birlikçileri süren belge-işi akış işlemcisi, bir Enterprise konusudur. Pro; motoru, sözleşmeleri ve yerel dayanıklı uygulamaları sağlar.

Pro olmadan, belgeleri NextPDF Core’un yazıcısıyla teker teker oluşturun; dayanıklı toplu akış, eşzamanlı yürütme ve tam olarak bir kez işleme, Pro eklentileridir. Bkz. /modules/writer/.

Bu sayfa yalnızca dışarıdan gözlemlenebilir davranışı ve desteklenen genel API yüzeyini belgeler. Dahili ad alanı yolları, yardımcı sınıflar, mekanizma tabloları, çalışma kitabı dosya adları ve bilet önekleri kapsam dışıdır.