ข้ามไปยังเนื้อหา

การใช้งาน NextPDF Symfony จริง

ใช้บันเดิลนี้กับรันไทม์ PHP ที่ทำงานต่อเนื่องระยะยาว บันเดิลกำหนดเอกสารให้เป็นแบบไม่ใช้ร่วมกัน ล็อก font registry หลังวอร์มอัป และรีเซ็ตแคชรูปภาพระหว่างแต่ละคำขอ สตรีมไฟล์ Portable Document Format (PDF) ขนาดใหญ่ และโอนงานหนักไปยัง Messenger worker

รันไทม์ที่ทำงานต่อเนื่องระยะยาวจะคงคอนเทนเนอร์ไว้ข้ามหลายคำขอ ดังนั้นสถานะของแต่ละคำขอต้องแยกออกจากกันอย่างชัดเจน FrankenPHP, RoadRunner และ Messenger worker ทำงานตามรูปแบบนี้ ไฟล์ services.php ของบันเดิลกำหนดวงจรชีวิตต่อไปนี้ ซึ่งตรวจสอบเทียบกับนิยามของเซอร์วิสแล้ว:

  • Document — แบบไม่ใช้ร่วมกัน nextpdf.document (และ alias PdfDocumentInterface / Document) จะถูกรีโซลฟ์เป็นอินสแตนซ์ใหม่ทุกครั้ง ภายใต้ PSR-11 (PHP Standard Recommendation 11) คอนเทนเนอร์สามารถคืนค่าที่แตกต่างกันในการเรียก get() แต่ละครั้งสำหรับ id เดียวกันได้อย่างถูกต้องตามข้อกำหนด (PSR-11 §1.1.2) รีโซลฟ์เอกสารแยกกันสำหรับแต่ละคำขอ อย่าเก็บเอกสารไว้ใช้ข้ามคำขอเป็นอันขาด
  • FontRegistry — ใช้ร่วมกันและถูกล็อก registry นี้เป็น singleton ตลอดอายุของโปรเซส หลังจาก warmup() (เมื่อ preload_fonts ไม่ว่าง) compiler pass จะเรียก lock() การล็อกนี้ป้องกันการแก้ไขขณะรันไทม์และการปนเปื้อนของสถานะฟอนต์ข้ามคำขอ
  • ImageRegistry — ใช้ร่วมกัน รีเซ็ตต่อแต่ละคำขอ แคชรูปภาพแบบ least recently used (LRU) ที่จำกัดขนาดไว้จะถูกใช้ร่วมกัน แต่ถูกแท็กด้วย kernel.reset ผ่านเมธอด reset ดังนั้น Symfony จึงล้างแคชนี้ระหว่างแต่ละคำขอบนรันไทม์ที่รองรับ kernel.reset
  • EInvoice contracts — แบบไม่ใช้ร่วมกัน เมื่อมีการ implement แบบ Premium อยู่ เซอร์วิส embedder, validator, profile และ schematron จะถูกลงทะเบียนเป็นแบบไม่ใช้ร่วมกัน บริบทของพาร์เซอร์ถูกจำกัดขอบเขตไว้ในแต่ละการเรียกและไม่รั่วไหลข้ามคำขอ

Inject PdfFactory ซึ่งเป็นตัวเก็บคอนฟิกแบบใช้ร่วมกันที่ไม่มีสถานะ จากนั้นเรียก create() ในแต่ละคำขอ:

public function __construct(private readonly PdfFactory $pdf) {}
public function action(): Response
{
$doc = $this->pdf->create(); // fresh, disposable
// ... build ...
return PdfResponse::inline($doc, 'document.pdf');
}

อย่า inject Document หรือ nextpdf.document เข้าไปในเซอร์วิสแบบใช้ร่วมกันที่ถูกเก็บไว้ข้ามคำขอ ให้รีโซลฟ์ภายในเมธอดที่มีขอบเขตอยู่ในคำขอแทน

PdfResponse::streamDownload() และ streamInline() คืนค่าเป็น StreamedResponse ที่มี callback ส่งเนื้อหา PDF ออกมาเป็นชิ้นขนาด 64 KB และฟลัชหลังจากแต่ละชิ้น จึงจำกัดขนาดบัฟเฟอร์ของการตอบกลับสำหรับเอกสารขนาดใหญ่ พฤติกรรมต่อไปนี้ได้รับการตรวจสอบเทียบกับ PdfResponse:

  • รูปแบบสตรีมจงใจ ละเว้น Content-Length เนื่องจากอ็อบเจกต์การตอบกลับไม่ทราบขนาดเนื้อหาล่วงหน้า แถบแสดงความคืบหน้าของการดาวน์โหลดและพร็อกซีบางตัวทำงานได้ดีกว่าเมื่อทราบความยาว ใช้ download() หรือ inline() แบบไม่สตรีมเมื่อเอกสารมีขนาดเล็กพอที่จะเก็บไว้ในหน่วยความจำและต้องการความยาวของเนื้อหา
  • รูปแบบสตรีมส่งเฮดเดอร์ความปลอดภัยชุดเดียวกัน และส่ง Cache-Control: private, max-age=0, must-revalidate เดียวกันกับรูปแบบบัฟเฟอร์

เลือกการสตรีมสำหรับรายงานขนาดหลายเมกะไบต์และการส่งออกแบบชุด เลือกรูปแบบบัฟเฟอร์สำหรับการตอบกลับขนาดเล็กที่ไวต่อ latency

โอนงานสร้างไปยัง Messenger เมื่อคำขอต้องตอบกลับอย่างรวดเร็ว หรือเมื่อการเรนเดอร์ใช้ทรัพยากรประมวลผลสูง

  1. implement PdfBuilderInterface สำหรับเอกสารแต่ละประเภท
  2. ลงทะเบียน builder ใน container.service_locator และเชื่อมเข้ากับ GeneratePdfHandler ในรูปแบบ $builderLocator
  3. กำหนดเส้นทาง GeneratePdfMessage ไปยัง transport ที่คงทน
  4. เรียกใช้ worker ด้วยอายุการทำงานที่จำกัด

รีไซเคิล worker เพื่อไม่ให้การจองหน่วยความจำที่รั่วไหลในไลบรารีของบุคคลที่สามขยายตัวอย่างไม่มีขีดจำกัด:

Terminal window
php bin/console messenger:consume async \
--limit=200 \
--memory-limit=256M \
--time-limit=3600

คีย์คอนฟิก messenger.timeout และ messenger.retries ของบันเดิลบันทึกค่า timeout ต่อข้อความและงบประมาณการลองใหม่ตามที่ตั้งใจไว้ บังคับใช้พฤติกรรมเดียวกันผ่านกลยุทธ์การลองใหม่ของ Symfony และแฟล็กของ worker

GeneratePdfMessage ตรวจสอบความถูกต้องของพาธเอาต์พุตตอนสร้างอ็อบเจกต์ GeneratePdfHandler ตรวจสอบความถูกต้องของพาธนี้อีกครั้งตอนประมวลผล ก่อนเขียนลงดิสก์ การตรวจสอบสองขั้นตอนนี้มีความสำคัญสำหรับงานแบบอะซิงโครนัส ข้อความอาจค้างอยู่ในคิวระหว่างการส่งและการประมวลผลได้ ดังนั้น handler จึงไม่เชื่อถือพาธที่อยู่ในคิวโดยปริยาย จำกัดสิทธิ์ระบบไฟล์ของ worker ให้อยู่เฉพาะไดเรกทอรีเอาต์พุตที่ตั้งใจไว้ เพื่อเป็นการป้องกันแบบหลายชั้น

เซอร์วิส FontRegistry และ ImageRegistry รับ Psr\Log\LoggerInterface แบบไม่บังคับได้ (ผูกด้วย nullOnInvalid()) เมื่อแอปพลิเคชันจัดเตรียม logger ไว้ registry เหล่านี้สามารถส่งข้อมูลวินิจฉัยผ่าน logger นั้นได้ logger เป็น collaborator แบบไม่บังคับและสลับเปลี่ยนได้ภายใต้ contract ของ PSR-3 logger (PSR-3) หากต้องการความชัดเจนในระดับคำขอ ให้บันทึก log รอบ ๆ PdfFactory::create() และ Messenger handler ในโค้ดแอปพลิเคชันของคุณ ใช้ messenger:consume -vv ระหว่างวิเคราะห์เหตุผิดปกติ

  • ปักหมุดเวอร์ชันหลัก (major) ของ nextpdf/core เพียงเวอร์ชันเดียวใน composer.json ของแอปพลิเคชัน (บันเดิลรองรับ ^3.0 || ^5.2)
  • ตรวจสอบให้แน่ใจว่า ext-mbstring และ ext-zlib เปิดใช้งานอยู่ใน PHP image ที่ดีพลอยแล้ว (มิฉะนั้นบันเดิลจะล้มเหลวทันทีตอนบูต)
  • กำหนด preload_fonts ล่วงหน้าด้วยฟอนต์ที่เอกสารของคุณใช้ เพื่อให้ registry วอร์มอัปและล็อกตอนบูตแทนที่จะเป็นตอนคำขอแรก
  • ชี้ cache_path ไปยังตำแหน่งที่เขียนได้และคงทนถาวร หากคุณพึ่งพา artifact ที่แคชไว้ข้ามการดีพลอย หากไม่เป็นเช่นนั้น ค่าเริ่มต้น %kernel.cache_dir% ก็เพียงพอ
  • เรียกใช้ php bin/console cache:warmup ระหว่างการดีพลอย เพื่อให้คอนเทนเนอร์ที่คอมไพล์แล้ว (รวมถึงการตรวจสอบส่วนขยายแบบไม่บังคับ) ถูกสร้างขึ้นก่อนที่จะมีทราฟฟิก
  • ใช้ Messenger transport ที่คงทน (ไม่ใช่ sync) สำหรับงานอะซิงโครนัสในการใช้งานจริง และรีไซเคิล worker ด้วย --limit / --memory-limit / --time-limit
  • การตอบกลับแบบสตรีมที่อยู่หลังพร็อกซีซึ่งทำบัฟเฟอร์ — พร็อกซีที่บัฟเฟอร์เนื้อหาทั้งหมดจะทำให้ประโยชน์ด้านหน่วยความจำหมดไป ตั้งค่าพร็อกซีให้สตรีมการตอบกลับ PDF หรือใช้การตอบกลับแบบบัฟเฟอร์ในกรณีนั้น
  • kernel.reset ไม่ถูกเรียกใช้ — บนรันไทม์ที่ไม่เรียก kernel.reset แคชรูปภาพจะถูกจำกัดขนาดด้วย image_cache_mb แต่จะไม่ถูกล้างระหว่างแต่ละคำขอ ให้กำหนดขนาดเพดานให้เหมาะสม
  • การเก็บเอกสารไว้ข้ามคำขอDocument ที่เก็บค้างไว้จากคำขอก่อนหน้าจะนำสถานะที่ล้าสมัยติดมาด้วย ให้รีโซลฟ์แยกกันต่อแต่ละคำขอผ่าน PdfFactory เสมอ

แต่ละแถวเป็นข้อกล่าวอ้างเชิงบรรทัดฐานในหน้านี้ ซึ่งปักหมุดไว้กับ reference_id แบบเต็มขนาด 64 หลักเลขฐานสิบหก จากคลังเอกสารขององค์กรพัฒนามาตรฐาน (SDO) ที่มีการควบคุมการเข้าถึง ที่มา (provenance) ของ manifest ของคลังเอกสารและ transport ที่ใช้ดึงข้อมูลอยู่ใน _sidecars/rag-citations.yaml

ข้อกำหนดข้อรหัสอ้างอิง (reference_id)ข้อกล่าวอ้าง
PSR-11psr_11_container#1.1.2.p3.bเซอร์วิสแบบไม่ใช้ร่วมกัน: คืนค่าที่แตกต่างกันในแต่ละการรีโซลฟ์
PSR-3psr_3_logger#x3.p17collaborator ของ logger แบบไม่บังคับ
  • /integrations/symfony/configuration/ — วงจรชีวิตของเซอร์วิสและพารามิเตอร์
  • /integrations/symfony/security-and-operations/ — เฮดเดอร์ของการตอบกลับ การตรวจสอบความถูกต้องของพาธ การจัดการคีย์
  • /integrations/symfony/troubleshooting/ — การวินิจฉัยตอนบูตและขณะรันไทม์
  • /integrations/symfony/quickstart/ — การตั้งค่าอะซิงโครนัสขั้นต่ำ