Penyebaran Terdistribusi
Melayani satu dokumen dari beberapa node
Ketika beberapa node melayani dokumen yang sama, node yang merender sebuah dokumen tidak selalu merupakan node yang menjawab permintaan halaman browser. Rilis ini membagi pekerjaan tersebut menjadi dua bagian eksplisit — sisi penulisan yang menerbitkan artefak dokumen ke penyimpanan bersama, dan sisi pembacaan yang melayani mereka dari node mana pun.
Jika aplikasi Anda saat ini memanggil UseDoconutWebFarm(...), halaman ini adalah penggantinya. Baik UseDoconutWebFarm maupun WebFarmOptions tidak ada dalam rilis ini.
Topologi Anda tidak berubah. Arahkan root bersama ke jalur UNC yang sama yang Anda gunakan hari ini dan setiap node tetap berfungsi seperti sebelumnya. Yang berubah adalah penerbitan menjadi operasi yang Anda panggil, bukan efek samping dari proses rendering.
Apa yang menggantikan middleware web-farm
Sebelumnya satu middleware melakukan semuanya: ia melayani gambar yang sudah dirender sebelumnya dari folder bersama dan memeriksa sementara node lain masih menulisnya. Penungguannya adalah anggaran buta — "blokir hingga tiga menit berharap halaman muncul".
Sekarang pekerjaan yang sama menjadi dua panggilan yang dapat Anda lihat dan pahami:
node A OpenDocument request
-> PublishAsync(...) writes pages, document info,
search index and metadata
into RootPath/{token}/
-> returns the token
node B ?token=...&page=7
-> UseDoconutCloud<FileShareCloudHandler>
-> reads RootPath/{token}/ and serves the pageKonfigurasi bersama yang dibutuhkan kedua sisi
Publisher menulis dengan FileShareConfig dan handler pembaca melayani dengan yang sama. Jika RootPath atau UsePerTokenSubfolders berbeda di antara keduanya, node lain akan menjawab 404. Bangun konfigurasi di satu tempat saja dan panggil dari kedua sisi — aplikasi referensi mempertahankan satu helper SharedStore.Config(...) untuk alasan ini:
internal static class SharedStore
{
public static FileShareConfig Config(string rootPath, bool asyncPublish) => new()
{
Location = CloudLocation.FileShare,
RootPath = rootPath, // e.g. \\fileserver\doconut
UsePerTokenSubfolders = true,
ReadReadyPollMs = asyncPublish ? 250 : 0,
};
}FileShareConfig berada di Doconut.Clouds, bersama dengan AzureConfig, AmazonConfig, GoogleCloudConfig, DropBoxConfig, RedisConfig, CDNConfig, dan FTPConfig. Pada perpustakaan sebelumnya, mereka berada di Doconut.Configs.Cloud; nama kelas tidak berubah.
| Properti | Tujuan |
|---|---|
Location | CloudLocation.FileShare untuk share UNC/lokal |
RootPath | Folder bersama yang dapat dijangkau oleh setiap node |
UsePerTokenSubfolders | Simpan artefak setiap dokumen di folder {token} masing-masing |
ReadReadyPollMs | Berapa lama sisi pembacaan menunggu halaman yang masih sedang ditulis; 0 menonaktifkan polling |
Sisi penulisan — menerbitkan dokumen
Suntikkan DistributedDocumentPublisher dan terbitkan alih-alih membuka sesi lokal. Satu panggilan merender dan menulis seluruh set artefak — halaman, info dokumen, indeks pencarian, dan metadata:
var shareConfig = SharedStore.Config(rootPath, asyncPublish: false);
var documentOptions = new DocOptions { TimeOut = 60 };
var config = new PdfConfig { AllowSearch = true };
var publishOptions = new DistributedDocumentPublishOptions
{
CleanUpStagingDirectory = true,
FirstPagePriority = true,
};
DistributedDocumentPublishResult result = await _publisher.PublishAsync(
pathToFile, shareConfig, config, documentOptions, publishOptions, ct);
return Content(result.Token);DistributedDocumentPublishResult membawa Token, ArtifactPath, TotalPages, dan Format. Token tersebut dikirim ke browser persis seperti token viewer normal.
Panggilan tunggal ini menggantikan pasangan sebelumnya — membuka dokumen ke dalam sesi lokal dan kemudian menyalurkan gambar ke share dengan ExportToPng(sharedPath). ExportToPng dan ExportToCloud tidak memiliki padanan di sini.
Sisi Baca — layani dari share
Pasang penangan FileShare pada cabang yang sama yang sudah dipanggil oleh klien:
app.UseDoconutResources();
app.MapWhen(
ctx => ctx.Request.Path.Value?.EndsWith("DocImage.axd", StringComparison.OrdinalIgnoreCase) == true,
branch => branch.UseDoconutCloud<FileShareCloudHandler>(options =>
{
options.Location = CloudLocation.FileShare;
options.CloudUploadConfig = SharedStore.Config(rootPath, asyncPublish: false);
}, "/"));UseDoconutCloud bersifat generik dalam rilis ini: penyedia adalah argumen tipe alih‑alih nilai Location yang dipilih di dalam middleware. Penangan dinamai <Provider>CloudHandler — FileShareCloudHandler, AzureCloudHandler, AmazonS3CloudHandler, GoogleCloudHandler, DropBoxCloudHandler, RedisCloudHandler, FTPCloudHandler, dan CDNCloudHandler.
Penangan CDN bersifat hanya-baca — ia melayani apa yang sudah ada di CDN; tidak mengunggah.
Prioritas Halaman Pertama dan HTTP 202
FirstPagePriority = true membuat halaman 1 dapat dilayani segera. Halaman selanjutnya menjawab HTTP 202 Accepted sampai mereka ditulis, alih‑alih memblokir permintaan.
Hal itu memindahkan penantian ke klien, di mana penantian terbatas dan terlihat. Aktifkan percobaan ulang pada widget:
const objViewer = $('#div_ctlDoc').docViewer({
BasePath: '/',
ResPath: 'doconut-res/images',
retryOn409: true // retries 202 (and legacy 409) readiness responses
});Klien yang tidak melakukan percobaan ulang menampilkan ubin rusak untuk halaman yang masih dirender. Anggaran percobaan ulang dan nilai bakunya (retryInitialDelayMs, retryBackoffFactor, retryMaxDelayMs, retryMaxAttempts, retryMaxTotalMs) didokumentasikan dalam KonfigurasiPenampil.
Pasangan ini — FirstPagePriority ditambah polling sisi baca — menggantikan pengaturan PageWaitTimeSeconds dan StartWaitFromPage sebelumnya. Kedua pengaturan tersebut tidak lagi ada.
Opsional: publikasikan di latar belakang
Secara default PublishAsync merender sebelum mengembalikan. Untuk mengembalikan segera setelah token dibuat dan membiarkan pekerja yang dihosting merender ke folder yang sama, daftarkan antrian opt‑in:
builder.Services.AddDoconut(options => { /* … */ });
builder.Services.AddDoconutDistributedAsyncPublish();Kemudian antrikan alih‑alih memublikasikan secara langsung, dan atur Async = true pada opsi publikasi. Antrian bersifat terbatas: ketika jenuh, EnqueueAsync melempar DistributedPublishQueueFullException. Tanggapi dengan kode 503 dan header Retry-After agar klien menurunkan kecepatan alih‑alih terhenti:
try
{
var token = await _publishQueue.EnqueueAsync(
pathToFile, shareConfig, config, documentOptions, publishOptions, ct);
return Content(token);
}
catch (DistributedPublishQueueFullException)
{
Response.Headers.RetryAfter = "5";
Response.StatusCode = 503;
return Content("The publish queue is full. Please retry.");
}Tanpa pendaftaran ini tidak ada yang terdaftar dan publikasi tetap sinkron — jalur default identik byte demi byte.
Ketika publikasi latar belakang diaktifkan, beri sisi baca ReadReadyPollMs yang tidak nol sehingga ia menunggu sebentar untuk halaman yang belum ditulis oleh pekerja.
Keamanan lintas node
Token yang terikat sesi mengasumsikan node yang melayani melihat permintaan pembuka. Pada sebuah farm node tidak melihatnya, sehingga pemeriksaan per‑sesi akan menolak permintaan yang sah. Itulah mengapa aplikasi referensi terdistribusi menetapkan UnsafeMode = true.
UnsafeMode = true bukanlah model keamanan — itu adalah penghapusan satu yang tidak lagi berlaku. Gantikan dengan tiket akses bertanda tangan, yang dapat diverifikasi secara independen oleh setiap node:
builder.Services.AddDoconutDistributedDocumentSecurity(options => { /* … */ });Jangan pernah membawa UnsafeMode = true kembali ke penyebaran satu‑node, dan jangan pernah memperlakukannya sebagai jalan pintas untuk pemeriksaan sesi yang gagal pada satu node — di sana perbaikan yang tepat adalah AddSession() / UseSession(). Lihat Sesi & Keamanan.
Menutup dokumen yang dipublikasikan
CloseDocument(token) pada Viewer yang disuntikkan membuang sesi lokal. Untuk menghapus artefak yang dipublikasikan dari share, penerbit menyediakan:
bool CloseDistributedDocument(FileShareConfig fileShareConfig, string token)Berikan FileShareConfig yang sama dengan yang dipakai saat dokumen dipublikasikan.
Pemetaan pengaturan demi pengaturan
| Sebelumnya | Sekarang |
|---|---|
UseDoconutWebFarm(new WebFarmOptions { … }) | PublishAsync(...) pada sisi penulisan plus UseDoconutCloud<FileShareCloudHandler>(...) pada sisi pembacaan |
WebFarmOptions.Path | FileShareConfig.RootPath |
PageWaitTimeSeconds / StartWaitFromPage | DistributedDocumentPublishOptions.FirstPagePriority plus FileShareConfig.ReadReadyPollMs |
viewer.OpenDocument(...) then viewer.ExportToPng(share) | satu panggilan PublishAsync(...) |
viewer.ExportToCloud(cloudConfig) | PublishAsync(...) dengan konfigurasi penyedia |
UseDoconutCloud(new CloudOptions { Location = … }) | UseDoconutCloud<THandler>(options => …, pathPrefix) |
DocOptions.IsWebfarm / WebfarmPath | Masih ada, ditulis IsWebFarm / WebFarmPath — tidak diperlukan pada jalur publikasi |
Doconut.Configs.Cloud | Doconut.Clouds |
Daftar Periksa
- Bangun
FileShareConfigdalam satu pembantu dan panggil dari kedua sisi. - Arahkan
RootPathke share yang sudah Anda gunakan. - Publikasikan dengan
PublishAsync(...); hapus semua pemanggilanExportToPng/ExportToCloud. - Layani dengan
UseDoconutCloud<FileShareCloudHandler>(...)pada cabang yang dipanggil klien. - Aktifkan
FirstPagePrioritydanretryOn409bersamaan, atau biarkan keduanya nonaktif. - Ganti pemeriksaan per-sesi dengan tiket akses yang ditandatangani — jangan kirim
UnsafeMode = truesaja. - Verifikasi dengan membuka dokumen pada satu node dan meminta halaman terlambat dari node lain.
Apakah halaman ini membantu?