การใช้งาน NextPDF Symfony จริง
ภาพรวมโดยย่อ
หัวข้อที่มีชื่อว่า “ภาพรวมโดยย่อ”ใช้บันเดิลนี้กับรันไทม์ PHP ที่ทำงานต่อเนื่องระยะยาว บันเดิลกำหนดเอกสารให้เป็นแบบไม่ใช้ร่วมกัน ล็อก font registry หลังวอร์มอัป และรีเซ็ตแคชรูปภาพระหว่างแต่ละคำขอ สตรีมไฟล์ Portable Document Format (PDF) ขนาดใหญ่ และโอนงานหนักไปยัง Messenger worker
วงจรชีวิตของเซอร์วิสที่ปลอดภัยสำหรับ worker
หัวข้อที่มีชื่อว่า “วงจรชีวิตของเซอร์วิสที่ปลอดภัยสำหรับ worker”รันไทม์ที่ทำงานต่อเนื่องระยะยาวจะคงคอนเทนเนอร์ไว้ข้ามหลายคำขอ ดังนั้นสถานะของแต่ละคำขอต้องแยกออกจากกันอย่างชัดเจน FrankenPHP, RoadRunner และ Messenger worker ทำงานตามรูปแบบนี้ ไฟล์ services.php ของบันเดิลกำหนดวงจรชีวิตต่อไปนี้ ซึ่งตรวจสอบเทียบกับนิยามของเซอร์วิสแล้ว:
- Document — แบบไม่ใช้ร่วมกัน
nextpdf.document(และ aliasPdfDocumentInterface/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 ที่แนะนำ
หัวข้อที่มีชื่อว่า “รูปแบบการ inject ที่แนะนำ”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 เมื่อคำขอต้องตอบกลับอย่างรวดเร็ว หรือเมื่อการเรนเดอร์ใช้ทรัพยากรประมวลผลสูง
- implement
PdfBuilderInterfaceสำหรับเอกสารแต่ละประเภท - ลงทะเบียน builder ใน
container.service_locatorและเชื่อมเข้ากับGeneratePdfHandlerในรูปแบบ$builderLocator - กำหนดเส้นทาง
GeneratePdfMessageไปยัง transport ที่คงทน - เรียกใช้ worker ด้วยอายุการทำงานที่จำกัด
อายุการทำงานที่จำกัดของ worker
หัวข้อที่มีชื่อว่า “อายุการทำงานที่จำกัดของ worker”รีไซเคิล worker เพื่อไม่ให้การจองหน่วยความจำที่รั่วไหลในไลบรารีของบุคคลที่สามขยายตัวอย่างไม่มีขีดจำกัด:
php bin/console messenger:consume async \ --limit=200 \ --memory-limit=256M \ --time-limit=3600คีย์คอนฟิก messenger.timeout และ messenger.retries ของบันเดิลบันทึกค่า timeout ต่อข้อความและงบประมาณการลองใหม่ตามที่ตั้งใจไว้ บังคับใช้พฤติกรรมเดียวกันผ่านกลยุทธ์การลองใหม่ของ Symfony และแฟล็กของ worker
ความปลอดภัยของพาธเอาต์พุตใน worker
หัวข้อที่มีชื่อว่า “ความปลอดภัยของพาธเอาต์พุตใน worker”GeneratePdfMessage ตรวจสอบความถูกต้องของพาธเอาต์พุตตอนสร้างอ็อบเจกต์ GeneratePdfHandler ตรวจสอบความถูกต้องของพาธนี้อีกครั้งตอนประมวลผล ก่อนเขียนลงดิสก์ การตรวจสอบสองขั้นตอนนี้มีความสำคัญสำหรับงานแบบอะซิงโครนัส ข้อความอาจค้างอยู่ในคิวระหว่างการส่งและการประมวลผลได้ ดังนั้น handler จึงไม่เชื่อถือพาธที่อยู่ในคิวโดยปริยาย จำกัดสิทธิ์ระบบไฟล์ของ worker ให้อยู่เฉพาะไดเรกทอรีเอาต์พุตที่ตั้งใจไว้ เพื่อเป็นการป้องกันแบบหลายชั้น
การสังเกตการณ์ระบบ (observability)
หัวข้อที่มีชื่อว่า “การสังเกตการณ์ระบบ (observability)”เซอร์วิส 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-11 | psr_11_container#1.1.2.p3.b | เซอร์วิสแบบไม่ใช้ร่วมกัน: คืนค่าที่แตกต่างกันในแต่ละการรีโซลฟ์ | |
| PSR-3 | psr_3_logger#x3.p17 | collaborator ของ logger แบบไม่บังคับ |
ดูเพิ่มเติม
หัวข้อที่มีชื่อว่า “ดูเพิ่มเติม”- /integrations/symfony/configuration/ — วงจรชีวิตของเซอร์วิสและพารามิเตอร์
- /integrations/symfony/security-and-operations/ — เฮดเดอร์ของการตอบกลับ การตรวจสอบความถูกต้องของพาธ การจัดการคีย์
- /integrations/symfony/troubleshooting/ — การวินิจฉัยตอนบูตและขณะรันไทม์
- /integrations/symfony/quickstart/ — การตั้งค่าอะซิงโครนัสขั้นต่ำ