\section{Por qué serverless + LaTeX}
Generación de PDF sin infraestructura
TeX Live pesa más de 4 GB. Empaquetarlo como capa de Lambda es lento, caro y frágil. La API de FormaTeX delega por completo la compilación, de modo que sus funciones siguen siendo pequeñas y rápidas.
Sin capa de TeX Live
Mantenga el paquete de despliegue de su Lambda por debajo de 10 MB. FormaTeX gestiona todo el entorno de TeX Live en infraestructura administrada.
Pague por compilación
Lambda factura por invocación; FormaTeX factura por compilación. Escale a cero cuando no haya actividad y alcance miles de PDF bajo carga.
Ejecución aislada
Cada compilación se ejecuta en un contenedor aislado en los servidores de FormaTeX. Su función Lambda nunca ejecuta LaTeX arbitrario en local.
\section{Handler en Python}
Handler de Lambda en Python
Usa solo la biblioteca estándar de Python más boto3 (preinstalado en todos los runtimes de Lambda). El PDF compilado se guarda en S3 y se devuelve la clave del objeto en el bucket.
- Runtime: Python 3.12 o posterior
- Dependencias: solo boto3 (incluido en el runtime de Lambda)
- Tiempo de espera: configure al menos 30 segundos para documentos complejos
import json
import os
import urllib.request
import boto3
def lambda_handler(event, context):
"""Compile LaTeX to PDF via FormaTeX API and store the result in S3."""
source = event.get("source", "")
engine = event.get("engine", "pdflatex")
if not source:
return {
"statusCode": 400,
"body": json.dumps({"error": "source is required"}),
}
# API key stored as a Lambda environment variable (or fetched from
# Secrets Manager at cold-start — see the IAM section below).
api_key = os.environ["FORMATEX_API_KEY"]
payload = json.dumps({"latex": source, "engine": engine}).encode()
req = urllib.request.Request(
"https://api.formatex.io/api/v1/compile",
data=payload,
headers={
"X-API-Key": api_key,
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(req, timeout=25) as resp:
pdf_bytes = resp.read()
s3 = boto3.client("s3")
bucket = os.environ["OUTPUT_BUCKET"]
key = f"pdfs/{context.aws_request_id}.pdf"
s3.put_object(Bucket=bucket, Key=key, Body=pdf_bytes, ContentType="application/pdf")
return {
"statusCode": 200,
"body": json.dumps({"bucket": bucket, "key": key}),
}\section{Handler en Node.js}
Handler de Lambda en Node.js
Handler con TypeScript como prioridad que usa solo los módulos integrados de Node.js y el cliente S3 del SDK v3 de AWS. La clave de API se almacena en caché en el ámbito del módulo, de modo que las invocaciones en caliente se saltan la consulta de la variable de entorno.
- Runtime: Node.js 20.x o posterior (ESM)
- Dependencias: @aws-sdk/client-s3 (incluido en el runtime de Lambda)
- Tiempo de espera: configure al menos 30 segundos
import https from "node:https"
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3"
const s3 = new S3Client({})
// Cache the API key across warm invocations
let cachedApiKey: string | undefined
export const handler = async (event: {
source: string
engine?: string
requestId?: string
}) => {
const { source, engine = "pdflatex" } = event
if (!source) {
return { statusCode: 400, body: JSON.stringify({ error: "source is required" }) }
}
if (!cachedApiKey) {
cachedApiKey = process.env.FORMATEX_API_KEY
}
if (!cachedApiKey) throw new Error("FORMATEX_API_KEY is not set")
const pdfBuffer = await compilePdf(cachedApiKey, source, engine)
const bucket = process.env.OUTPUT_BUCKET!
const key = `pdfs/${event.requestId ?? Date.now()}.pdf`
await s3.send(
new PutObjectCommand({
Bucket: bucket,
Key: key,
Body: pdfBuffer,
ContentType: "application/pdf",
}),
)
return { statusCode: 200, body: JSON.stringify({ bucket, key }) }
}
function compilePdf(apiKey: string, source: string, engine: string): Promise<Buffer> {
return new Promise((resolve, reject) => {
const body = JSON.stringify({ latex: source, engine })
const options = {
hostname: "api.formatex.io",
path: "/api/v1/compile",
method: "POST",
headers: {
"X-API-Key": apiKey,
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(body),
},
}
const req = https.request(options, (res) => {
const chunks: Buffer[] = []
res.on("data", (c: Buffer) => chunks.push(c))
res.on("end", () => {
if (res.statusCode !== 200) {
reject(new Error(`FormaTeX error: HTTP ${res.statusCode}`))
} else {
resolve(Buffer.concat(chunks))
}
})
})
req.on("error", reject)
req.write(body)
req.end()
})
}\section{Permisos de IAM}
Guardar la clave de API en Secrets Manager
En cargas de trabajo de producción, guarde su clave de API de FormaTeX en AWS Secrets Manager en lugar de en una variable de entorno sin protección. Adjunte la siguiente política al rol de ejecución de su Lambda y obtenga el secreto en el arranque en frío.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadFormaTeXApiKey",
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:formatex/api-key-*"
},
{
"Sid": "WriteOutputBucket",
"Effect": "Allow",
"Action": ["s3:PutObject"],
"Resource": "arn:aws:s3:::your-output-bucket/pdfs/*"
}
]
}
# Store the secret in Secrets Manager (one-time setup):
aws secretsmanager create-secret \
--name formatex/api-key \
--secret-string '{"FORMATEX_API_KEY":"your-key-here"}'
# Then fetch it at cold-start in Python:
# import boto3, json
# secret = boto3.client("secretsmanager").get_secret_value(SecretId="formatex/api-key")
# api_key = json.loads(secret["SecretString"])["FORMATEX_API_KEY"]\section{Consideraciones sobre el arranque en frío}
Minimice la latencia en los arranques en frío
Almacene los secretos en caché en el ámbito del módulo
Obtenga su clave de API de Secrets Manager una sola vez, fuera de la función handler. El valor se reutiliza en todas las invocaciones en caliente sin otra llamada de red.
Use concurrencia aprovisionada en las rutas sensibles a la latencia
Active la concurrencia aprovisionada en la versión de Lambda para eliminar por completo los arranques en frío en los endpoints de generación de PDF orientados al usuario. Use concurrencia bajo demanda para los trabajos por lotes en segundo plano.
Configure un tiempo de espera realista
Los documentos LaTeX complejos con TikZ, bibliografía o varias pasadas de compilación pueden tardar de 10 a 20 segundos. Configure el tiempo de espera de Lambda en al menos 30 segundos y ajuste el de su integración con API Gateway o ALB para que coincida.
\section{Guías relacionadas}
Más guías de SDK y lenguajes
La API de FormaTeX es un endpoint HTTP sencillo. Úsela desde cualquier lenguaje o runtime.

