Bỏ qua để đến nội dung
getnextpdf.com

Chạy NextPDF trên các nền tảng serverless

Engine core NextPDF gốc, in-process, là một khối lượng công việc serverless gần như lý tưởng. Nó là pure PHP chạy ngay bên trong tiến trình của bạncomposer require nextpdf/core, dựng một tài liệu, lấy các byte. Không có binary bên ngoài để khởi sinh, không có trình duyệt headless, không có daemon để giữ sống, và không có socket tới một dịch vụ sidecar. Một hàm dựng PDF khởi động lạnh, chạy PHP của bạn, trả về các byte, rồi thoát. Điều đó ánh xạ gọn gàng sang AWS Lambda (qua runtime Bref), Google Cloud Run, và AWS App Runner.

Trang này bao quát việc triển khai engine gốc đó lên ba runtime ấy và tập nhỏ các ràng buộc thực sự mà chúng áp đặt:

  • hệ thống tệp của runtime không bền: Lambda chỉ bảo đảm một /tmp ghi được (512 MB mặc định, có thể cấu hình lên tới 10 GB), trong khi các runtime container (Cloud Run, App Runner) có một hệ thống tệp phù du, phạm vi-container — dù theo cách nào, phông chữ phải đi cùng bên trong gói triển khai hoặc image và được đăng ký trong PHP (engine không đọc biến môi trường đường dẫn phông chữ nào);
  • cold start phải trả giá cho việc autoload và bất kỳ thao tác làm ấm phông chữ nào, nên hãy làm ấm FontRegistry một lần cho mỗi container, không phải cho mỗi lần gọi;
  • kích thước gói, bộ nhớ, và timeout phải được định cỡ theo bản dựng, không phải theo một request tầm thường.

Trang này chỉ dành cho engine gốc. Cầu nối Chrome (writeHtmlChrome qua gói gợi ý nextpdf/artisan) là một câu chuyện khác, nặng nề hơn: nó shell ra một Chromium headless qua symfony/process, thứ mà một zip Lambda thuần hoặc một container gọn nhẹ không chứa. Chạy Chromium trên Lambda nghĩa là một layer tùy chỉnh kèm trình duyệt và các thư viện chia sẻ của nó, các gói lớn hơn nhiều, và cold start dài hơn nhiều — nằm ngoài phạm vi ở đây. Engine trần không cần bất kỳ thứ nào trong số đó.

Trước khi bắt đầu, hãy xác nhận những phần này đã sẵn sàng:

  • Ứng dụng của bạn đã có composer.jsoncomposer.lock được commit, với nextpdf/core là một dependency.
  • Bạn có các tệp phông chữ bạn định nhúng, và bạn được cấp phép để nhúng chúng.
  • Bạn có chuỗi công cụ cho mục tiêu của mình — Bref CLI và framework serverless cho Lambda, hoặc một bản dựng container cho Cloud Run / App Runner.

Đọc thẳng từ gói, nextpdf/core yêu cầu php: >=8.4 <9.0 và một tập nhỏ các extension PHP — ext-mbstring, ext-intl, ext-gd, ext-openssl, ext-zlib, và ext-curl. Các layer PHP Bref tiêu chuẩn đóng gói sẵn từng cái trong số đó. Các image container php:8.4 chính thức cung cấp sẵn openssl, curl, và zlib, nhưng mbstring, gd, và intl thì không được đóng gói — chúng yêu cầu cài đặt các dependency hệ thống và bật các extension bằng docker-php-ext-install (xem hướng dẫn triển khai Docker). Trên Bref không có gì kỳ lạ phải biên dịch; trên lối container bạn bật ba extension đó trong bản dựng image cho engine trần.

Điều khiến sự phù hợp trở nên gọn gàng là những gì engine không làm:

  • Không có tiến trình con cho lối core. Dựng một tài liệu và gọi getPdfData() là PHP in-process từ đầu tới cuối. Dependency symfony/process tồn tại cho cầu nối Chrome tùy chọn, không phải cho kết xuất gốc — việc tạo PDF gốc không bao giờ khởi sinh một tiến trình.
  • Không có trạng thái dai dẳng. Mỗi lần gọi dựng một tài liệu mới và trả về các byte. Không có gì phải sống sót giữa các request ngoại trừ container ấm, thứ bạn khai thác để làm ấm phông chữ (bên dưới) nhưng không bao giờ dựa vào cho tính đúng đắn.
  • Không cần thư mục làm việc ghi được. Engine dựng PDF trong bộ nhớ và trả về nó dưới dạng một chuỗi; nó chỉ chạm đĩa nếu bạn gọi save(). Trên serverless bạn không gọi — bạn trả về các byte — nên việc thiếu một hệ thống tệp bền không bao giờ cắn vào lối dựng.

Ràng buộc cứng duy nhất: không có hệ thống tệp ghi được bền

Phần tiêu đề “Ràng buộc cứng duy nhất: không có hệ thống tệp ghi được bền”

Hệ thống tệp triển khai không bền, nhưng mô hình khác nhau tùy runtime. AWS Lambda chỉ bảo đảm một /tmp ghi được (512 MB mặc định, có thể cấu hình lên tới 10 GB); phần còn lại của hệ thống tệp hàm là chỉ-đọc. Các runtime container (Cloud Run, App Runner) có một hệ thống tệp ghi được phù du, phạm vi-container thay vì một mô hình chỉ-/tmp — nhưng bất cứ thứ gì ghi vào đó đều mất khi container được tái chế, nên nó là không gian nháp, không phải lưu trữ. Trong mọi trường hợp, hãy ưu tiên /tmp hoặc một volume đã cấu hình để dàn dựng, và không bao giờ dựa vào việc ghi vào đường dẫn image ứng dụng như lưu trữ bền. Hai hệ quả theo sau.

Đừng bao giờ gọi save() với kỳ vọng đầu ra bền. NextPDF\Core\Document phơi ra cả save(string $path): voidgetPdfData(): string. Trên serverless bạn dùng getPdfData() và trả về hoặc tải lên các byte — đừng coi việc ghi vào thư mục ứng dụng là lưu trữ dai dẳng. Nếu bạn buộc phải dàn dựng một tệp (ví dụ, để multipart-upload tới lưu trữ đối tượng), hãy ghi dưới /tmp (hoặc một volume đã cấu hình) và dọn dẹp, nhớ rằng trên một container ấm không gian nháp này tồn tại qua các lần gọi và tính vào giới hạn kích thước của nó.

use NextPDF\Core\Document;
// Right for serverless: get the bytes, return or upload them.
$pdf = $document->getPdfData(); // string of PDF bytes, built in memory
// Avoid on serverless: save() writes to disk. On Lambda the application
// directory is read-only; on Cloud Run / App Runner it is writable but
// ephemeral (lost on container recycle). Neither is durable storage.
// $document->save('/var/task/out.pdf'); // not durable — return the bytes instead

Đừng cài phông chữ OS lúc runtime, và đừng dựa vào việc tự động khám phá phông chữ; hãy đóng gói các tệp phông chữ của bạn cho sản xuất. Trên Lambda hệ thống tệp chỉ-đọc chặn thẳng apt-get install fonts-*; trên một runtime container, bất kỳ thao tác cài đặt lúc runtime nào cũng rơi vào một hệ thống tệp phù du và mất ở lần tái chế kế tiếp. Và dù sao nó cũng không giúp gì, vì engine gốc không đọc các phông chữ OS/fontconfig — nó chỉ phân giải phông chữ từ các tệp bạn đăng ký. Vì vậy với sản xuất, các tệp phông chữ phải đi kèm bên trong tạo phẩm triển khai. Nếu bạn chủ ý lấy các tệp phông chữ vào /tmp hoặc một volume đã cấu hình, bạn phải đăng ký chúng tường minh với registry phông chữ và chấp nhận chi phí cold-start và độ tin cậy tăng thêm — đó không phải là một mẫu sản xuất được khuyến nghị.

Đóng gói và đăng ký phông chữ trong gói hoặc image

Phần tiêu đề “Đóng gói và đăng ký phông chữ trong gói hoặc image”

Engine gốc phân giải phông chữ từ các tệp phông chữ thông qua NextPDF\Typography\FontRegistry, không phải từ fontconfig hay các phông chữ được OS cài đặt. Trên serverless điều này không thể thương lượng: không có hệ thống tệp dai dẳng để đặt phông chữ vào sau khi triển khai, nên chúng đi kèm bên trong gói (một zip hoặc layer Lambda) hoặc bên trong image (Cloud Run / App Runner).

Đóng gói các tệp .ttf / .otf / .ttc của bạn dưới một thư mục trong dự án — resources/fonts/ là quy ước — để chúng được đưa vào tạo phẩm. Rồi đăng ký thư mục đó trong PHP. Engine không đọc biến môi trường đường dẫn phông chữ nào: NEXTPDF_FONTS_PATH là giá trị mặc định của khóa cấu hình fonts_path của gói nextpdf/laravel (env('NEXTPDF_FONTS_PATH', resource_path('fonts'))) và chỉ được tiêu thụ bởi tích hợp framework đó, không phải bởi nextpdf/core. Một hàm trần phải khởi tạo registry với thư mục đã đóng gói:

use NextPDF\Typography\FontRegistry;
use NextPDF\Core\DocumentFactory;
use NextPDF\Graphics\ImageRegistry;
// Register the directory the deployment artifact bundled the fonts into.
// On Lambda/Bref the code root is /var/task; adjust for your runtime.
$registry = new FontRegistry(__DIR__ . '/resources/fonts');
// (equivalently, $registry->addFontDirectory(__DIR__ . '/resources/fonts');)
$factory = new DocumentFactory($registry, new ImageRegistry(maxCacheBytes: 0));
$document = $factory->create();

Đó là toàn bộ mối quan tâm serverless về phông chữ. Các quy tắc đặt tên tệp, toàn bộ API registry, và việc xử lý hệ thống tệp không bền nằm trên trang chuyên biệt — đừng nhân bản chúng ở đây. Hãy đọc Cung cấp phông chữ cho engine gốc trong sản xuất để biết mẫu đầy đủ, và đăng ký đúng thư mục bạn đã đóng gói. Hướng dẫn triển khai Docker bao quát việc đóng gói tương đương phía image cho trường hợp Cloud Run / App Runner.

Cold start: làm ấm FontRegistry một lần cho mỗi container

Phần tiêu đề “Cold start: làm ấm FontRegistry một lần cho mỗi container”

Một cold start phải trả giá cho việc bootstrap PHP, autoloader đã tối ưu của Composer, và bất kỳ thao tác phân tích phông chữ nào mà bản dựng đầu tiên kích hoạt. Bạn không thể tránh việc bootstrap, nhưng bạn có thể đưa công việc phông chữ ra khỏi lối nóng và tái sử dụng nó qua các lần gọi ấm.

Khởi tạo FontRegistryDocumentFactory một lần, bên ngoài handler, để chúng sống suốt đời container và được tái sử dụng ở mỗi lần gọi ấm. Tùy chọn, gọi warmup() với các tệp phông chữ bạn biết mình sẽ dùng, để chúng được phân tích trong lúc khởi tạo thay vì ở lần kết xuất đầu tiên, rồi lock() registry để trạng thái đã phân tích của nó bị đóng băng và không có thay đổi theo từng lần gọi nào có thể tranh chấp:

use NextPDF\Typography\FontRegistry;
use NextPDF\Core\DocumentFactory;
use NextPDF\Graphics\ImageRegistry;
// Container-scoped, built once at cold start (module scope, not per request).
$fontsDir = __DIR__ . '/resources/fonts';
$registry = new FontRegistry($fontsDir);
// Parse the fonts you will actually use now, so the first render does not.
$registry->warmup([
$fontsDir . '/liberation/LiberationSans-Regular.ttf',
$fontsDir . '/liberation/LiberationSans-Bold.ttf',
]);
// Freeze the parsed state for the life of the warm container.
$registry->lock();
$factory = new DocumentFactory($registry, new ImageRegistry(maxCacheBytes: 0));
// Each invocation: fresh document from the shared, warm factory.
$handler = static function (array $event) use ($factory): string {
$document = $factory->create();
$document->addPage();
$document->cell(0, 10, 'Hello from serverless', newLine: true);
return $document->getPdfData();
};

Gọi warmup() trước lock() — registry bị đóng băng một khi đã khóa, nên một lần warmup sau đó sẽ phát ra lỗi cấu hình. Hãy coi một phông chữ không tải được lúc warmup là một lỗi thời điểm triển khai, không phải chi tiết runtime: xác thực rằng mọi đường dẫn phông chữ bạn định làm ấm thực sự tồn tại và phân tích được lúc khởi động, và làm thất bại lần triển khai (hoặc health check của bạn) nếu một đường dẫn không thỏa, thay vì để một đường dẫn gõ sai lộ ra sau này dưới dạng các glyph thiếu. Hãy giữ danh sách warmup gói gọn trong các phông chữ mà một lần gọi điển hình cần; làm ấm một họ phông lớn mà bạn hiếm khi dùng chỉ kéo dài mọi cold start.

Bref cung cấp runtime PHP cho Lambda dưới dạng một layer đã xuất bản và một plugin serverless.yml. Runtime php-84 đã đi kèm sẵn các extension mà nextpdf/core cần, nên bạn triển khai mã và phông chữ của mình rồi trỏ một hàm vào một handler. Một serverless.yml tối thiểu:

service: nextpdf-serverless
provider:
name: aws
region: us-east-1
runtime: provided.al2023
plugins:
- ./vendor/bref/bref
functions:
generate:
handler: handler.php
description: Generate a PDF with the native NextPDF engine
runtime: php-84
memorySize: 1024 # size to the build; see "Sizing" below
timeout: 30 # seconds; raise for large documents
# The Lambda filesystem is read-only except /tmp. Fonts ship in the
# package under resources/fonts and are registered in the handler.

Handler dựng tài liệu với factory ấm, phạm vi-container và trả về các byte. Với một HTTP API, trả chúng dưới dạng base64 với content type application/pdf để API Gateway coi body là nhị phân; với một trigger invoke hoặc queue, tải các byte lên lưu trữ đối tượng và trả về khóa:

handler.php (outline)
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Typography\FontRegistry;
// --- Cold-start: built once per container, reused across warm invocations. ---
$fontsDir = __DIR__ . '/resources/fonts';
$registry = new FontRegistry($fontsDir);
$registry->warmup([$fontsDir . '/liberation/LiberationSans-Regular.ttf']);
$registry->lock();
$factory = new DocumentFactory($registry, new ImageRegistry(maxCacheBytes: 0));
// --- Per-invocation handler. ---
return static function (array $event) use ($factory): array {
$document = $factory->create();
$document->addPage();
$document->cell(0, 10, 'Invoice', newLine: true);
// getPdfData() materializes the whole PDF in memory and returns it.
$bytes = $document->getPdfData();
return [
'statusCode' => 200,
'isBase64Encoded' => true,
'headers' => ['Content-Type' => 'application/pdf'],
'body' => base64_encode($bytes),
];
};

Hãy xác minh gói chứa một môi trường khỏe mạnh trước khi đấu nối lưu lượng vào nó. nextpdf/core đi kèm một CLI cài tại vendor/bin/nextpdf mà lệnh doctor của nó báo cáo về đúng các extension mà engine cần. Chạy nó một lần đối với cùng image runtime hoặc layer để xác nhận PHP 8.4 và mọi extension yêu cầu đều hiện diện.

Cloud Run và App Runner chạy một container chứ không phải một hàm được nén, nên bản dựng là image Docker từ Đóng gói một ứng dụng NextPDF, không phải một gói Bref. Các ràng buộc engine-gốc là giống hệt: đóng gói các phông chữ vào image, đăng ký thư mục đã đóng gói trong PHP, chạy không đặc quyền, và coi hệ thống tệp là không bền. Khác với mô hình chỉ-/tmp của Lambda, một container Cloud Run / App Runner có một hệ thống tệp ghi được phù du, phạm vi-container — nhưng nó được đặt lại ở mỗi lần tái chế, nên hãy dùng /tmp (một tmpfs trên Cloud Run) hoặc một volume đã cấu hình cho không gian nháp và không bao giờ dựa vào việc ghi vào đường dẫn image ứng dụng như lưu trữ bền.

Những khác biệt so với Lambda là về vận hành, không phải cấu trúc:

  • Container có thể giữ ấm qua các request dưới một thiết lập concurrency, nên việc làm ấm FontRegistry/DocumentFactory phạm vi-container ở trên có lợi qua nhiều request, không chỉ lần gọi kế tiếp.
  • Bạn phục vụ qua HTTP (một SAPI FPM hoặc máy chủ PHP tích hợp) chứ không phải một sự kiện invoke, nên bạn trả các byte qua response của framework. Với một tài liệu lớn, hãy trả chúng dưới dạng một response được stream — xem Stream một PDF lớn được tạo dưới dạng một HTTP response.
  • Timeout request và bộ nhớ được đặt trên dịch vụ (timeout / bộ nhớ dịch vụ Cloud Run; cấu hình instance App Runner) chứ không phải theo từng hàm.

Mọi thứ còn lại — tập extension, việc đăng ký phông chữ, lệnh gọi đầu ra getPdfData() — là cùng mã như handler Lambda.

  • Kích thước gói và image. Tạo phẩm mang theo vendor/ (chỉ sản xuất — cài với --no-dev) và các phông chữ đã đóng gói của bạn. Phông chữ chiếm phần lớn: một họ CJK đầy đủ nặng hàng chục megabyte. Chỉ đi kèm các phông chữ bạn thực sự kết xuất để giữ gói Lambda dưới các giới hạn của nó và image nhỏ, điều này cũng rút ngắn các cold start. Họ Liberation đã đóng gói (resources/fonts/liberation/) nhỏ và phủ việc thay thế Helvetica tương thích về metric.
  • Bộ nhớ. getPdfData() dựng toàn bộ tài liệu trong bộ nhớ và trả về nó dưới dạng một chuỗi, nên đỉnh bộ nhớ xấp xỉ kích thước của một PDF hoàn chỉnh cộng với tập làm việc của bản dựng. Hãy định cỡ bộ nhớ hàm/container theo tài liệu lớn nhất bạn tạo, không phải theo trung bình. Trên Lambda, bộ nhớ cũng co giãn CPU, nên nhiều bộ nhớ hơn thường nghĩa là bản dựng nhanh hơn và một lần chạy rẻ hơn dù tỷ giá theo từng mili-giây cao hơn — hãy đo cả hai. Một tài liệu vài trang thoải mái ở 512–1024 MB; các tài liệu nặng hình ảnh hoặc nhiều trang cần nhiều hơn.
  • Timeout. Bản dựng, không phải việc truyền, chiếm phần lớn ngân sách request. Đặt timeout hàm cao hơn thời gian dựng tệ nhất với một biên độ. Nếu một tài liệu đủ lớn để có nguy cơ timeout, hãy chuyển việc tạo sang một trigger bất đồng bộ (một Lambda dựa-trên-queue hoặc một Cloud Run job) ghi kết quả vào lưu trữ đối tượng thay vì chặn một request đồng bộ.
  • Kích thước /tmp. Nếu bạn dàn dựng bất cứ thứ gì dưới /tmp, hãy tính tới giới hạn kích thước của nó và nhớ rằng nó tồn tại qua các lần gọi ấm — hãy dọn dẹp, nếu không một container sống lâu sẽ từ từ làm đầy nó.
  • Không có save() bền vào thư mục ứng dụng. Hệ thống tệp triển khai không bền — thư mục ứng dụng của Lambda là chỉ-đọc (chỉ /tmp chấp nhận ghi), và một hệ thống tệp container Cloud Run / App Runner ghi được nhưng phù du. Hãy dùng getPdfData() và trả về/tải lên các byte; dàn dựng dưới /tmp hoặc một volume đã cấu hình nếu bạn buộc phải.
  • Đừng dựa vào việc tự động khám phá phông chữ. Đừng cài phông chữ OS lúc runtime, và đừng dựa vào việc tự động khám phá phông chữ; hãy đóng gói các tệp phông chữ của bạn cho sản xuất. Engine gốc không đọc các phông chữ OS/fontconfig — nó chỉ phân giải các tệp bạn đăng ký. Nếu bạn chủ ý lấy các tệp phông chữ vào /tmp hoặc một volume đã cấu hình, bạn phải đăng ký chúng tường minh với registry phông chữ và chấp nhận chi phí cold-start và độ tin cậy tăng thêm. Hãy đóng gói và đăng ký các tệp. Xem trang phông chữ đã liên kết ở trên.
  • NEXTPDF_FONTS_PATH không làm gì cho engine trần. Nó là giá trị mặc định cấu hình của nextpdf/laravel, không phải một biến mà nextpdf/core đọc. Một handler Bref trần chỉ đặt biến đó sẽ không đăng ký phông chữ nào và kết xuất ra tofu.
  • Cầu nối Chrome không vừa với một hàm thuần. writeHtmlChrome cần một Chromium headless và lối tiến trình con symfony/process. Đặt Chromium trên Lambda yêu cầu một layer tùy chỉnh kèm trình duyệt và các thư viện của nó, các gói lớn hơn nhiều, và cold start dài. Engine gốc và writeHtml không cần bất kỳ thứ nào trong số đó — hãy ưu tiên chúng trên serverless.
  • Chi phí cold-start là autoload cộng với phân tích phông chữ. Dùng --optimize-autoloader cho bản cài sản xuất và làm ấm registry một lần cho mỗi container. Đừng làm ấm các phông chữ bạn hiếm khi dùng.
  • API Gateway cần xử lý nhị phân. Trả isBase64Encoded: true với Content-Type: application/pdf, và cấu hình API để coi application/pdf là một loại media nhị phân, nếu không client nhận các byte hỏng.
  • Premium và ionCube là một mối quan tâm tạo phẩm nặng hơn. Các bản build NextPDF Pro / Enterprise được mã hóa bằng ionCube cần ionCube Loader khớp với đúng bản build PHP trong runtime, thứ mà một layer Bref tiêu chuẩn không bao gồm. Điều đó nằm ngoài phạm vi cho một lần triển khai serverless core.
  • Không đi kèm dependency dev. Cài với --no-dev để các công cụ kiểm thử và phân tích không bao giờ lọt vào gói hàm hoặc image.
  • Xác thực đầu vào trước khi dựng. Một bản dựng PDF được điều khiển bởi đầu vào request là một vector làm cạn kiệt bộ nhớ; hãy từ chối các đầu vào ngoài khoảng hoặc quá cỡ ở biên trước khi bất kỳ công việc dựng nào chạy, và giới hạn concurrency để lưu lượng cao không nhân đỉnh bộ nhớ thành một thất bại out-of-memory.
  • Giữ phông chữ và giấy phép ngoài các tạo phẩm công khai. Chỉ đóng gói các phông chữ bạn được cấp phép để nhúng, và đừng bao giờ nướng một tệp giấy phép premium vào một image hoặc layer được đẩy công khai — hãy cung cấp nó lúc runtime qua một giá trị môi trường hoặc trình quản lý bí mật.
  • Đặc quyền tối thiểu. Chỉ cấp cho hàm/dịch vụ những quyền IAM mà nó cần (ví dụ, quyền ghi vào đúng một bucket đầu ra), và chạy container không đặc quyền như hướng dẫn Docker chỉ ra.

Hướng dẫn này không đưa ra tuyên bố tiêu chuẩn quy phạm nào. Các sự kiện nền tảng được đọc trực tiếp từ gói nextpdf/core: ràng buộc php: >=8.4 <9.0 và các extension yêu cầu ext-mbstring, ext-intl, ext-gd, ext-openssl, ext-zlib, và ext-curl. Layer runtime PHP-8.4 Bref tiêu chuẩn đóng gói cả sáu; image php:8.4 chính thức cung cấp openssl, curl, và zlib, nhưng mbstring, gd, và intl phải được cài và bật trong bản dựng image bằng docker-php-ext-install (xem trang Docker). Lệnh gọi đầu ra là bề mặt core thực sự NextPDF\Core\Document::getPdfData(): string (anh em đĩa của nó là save(string $path): void). Phông chữ được đăng ký qua NextPDF\Typography\FontRegistry — đối số hàm khởi tạo thư mục của nó / addFontDirectory(), cùng warmup(array $fontFiles)lock() cho mẫu cold-start — được đấu nối qua NextPDF\Core\DocumentFactory::create(). NEXTPDF_FONTS_PATH là khóa cấu hình fonts_path của gói nextpdf/laravel (env('NEXTPDF_FONTS_PATH', resource_path('fonts'))), không phải một biến mà nextpdf/core đọc. Lệnh doctor của CLI nextpdf được khai báo là "bin": ["bin/nextpdf"] trong gói và cài tại vendor/bin/nextpdf trong một ứng dụng tiêu thụ. Các tên runtime Bref và hành vi AWS Lambda / Cloud Run / App Runner là những tính năng được ghi tài liệu của các nhà cung cấp đó.