⚡ Rendimiento y velocidad
Guía para responder con datos —y no con suposiciones— a la pregunta ¿por qué una factura tarda más que antes?, sobre todo al pasar de una instalación 2025 a la 2026.
El API cronometra cada emisión y reparte su tiempo por etapa (arranque, DIAN, PDF, firma,
AttachedDocument, correo, S3). La medición es interna: no aparece en ninguna pantalla, queda
guardada en la tabla monitoring_slow_requests para consultarla cuando haga falta.
Esta versión incluye migraciones de base de datos. Después de actualizar el código ejecute
php artisan migrate. Si usa Docker, además hay que reconstruir la imagen para que quede
activo OPcache (ver el punto 1).
1. Active OPcache antes que nada
PHP 8.3 sin OPcache es más lento que PHP 7.4 con OPcache: recompila las clases del proyecto en cada petición. Es la primera causa de que el 2026 se sienta más lento que el 2025.
En Docker ya viene activo de fábrica, pero hay que reconstruir la imagen, no solo reiniciarla:
docker compose build php_api scheduling_api
docker compose up -d
docker compose exec php_api php -i | grep -E "opcache.enable|memory_consumption"
Sin Docker, agregue estos valores al php.ini y reinicie php-fpm
(systemctl restart php8.3-fpm):
opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=2
En Windows (Laragon, solo para pruebas) además hay que descomentar
zend_extension=php_opcache.dll en el php.ini de la versión 8.3 y reiniciar Apache.
php -i | grep opcache ejecutado en consola siempre dirá que está apagado: en la CLI lo está a
propósito. Verifíquelo dentro del contenedor del API o con un phpinfo() temporal.
2. Mida la emisión por etapas
-
En el
.env, baje el umbral para que se registren todas las peticiones y no solo las que pasan de 3 segundos:MONITOR_SLOW_REQUEST_MS=0php artisan config:clear -
Emita 3 o 4 facturas reales, mejor desde su software de facturación que desde Postman, para que el tiempo incluya la red.
-
Consulte el resultado en la base de datos:
SELECT created_at, route, duration_ms, bootstrap_ms, query_count, query_time_ms,
stages, top_queries
FROM monitoring_slow_requests
ORDER BY id DESC
LIMIT 10; -
Devuelva el umbral a su valor normal (
MONITOR_SLOW_REQUEST_MS=3000o quite la línea) y vuelva a ejecutarphp artisan config:clear.
Déjelo así solo el rato que dure la medición. Las filas antiguas se borran solas a los días que
indique MONITOR_RETENTION_DAYS (7 por defecto).
Cómo leer el reparto
La columna stages trae los milisegundos de cada etapa y top_queries las consultas que más se
repitieron en esa petición.
| Etapa | Qué incluye | Si es la más alta |
|---|---|---|
Arranque (bootstrap_ms) | Desde que php-fpm recibe la petición hasta el primer middleware | Es entorno, no código: revise OPcache |
dian | El envío completo al servicio de la DIAN, ida y vuelta | No depende del API: es la DIAN o la red del servidor |
pdf | Plantilla, QR, logo y escritura del PDF | Plantillas con muchas líneas o un logo demasiado pesado |
firma_xml | Guardar el XML firmado y comprimirlo | Disco lento |
attacheddocument | Armar y firmar el AttachedDocument | Es otra firma XML: cientos de milisegundos son normales |
correo | El envío del documento al cliente, que es sincrónico | Un SMTP lento hace esperar a quien factura |
s3 | La subida de los archivos del documento | La empresa tiene el almacenamiento en s3 o dual |
query_time_ms | La suma del tiempo de todas las consultas | La base de datos está lejos, saturada o con tablas enormes |
Si la suma de las etapas es mucho menor que duration_ms, el tiempo se está yendo en el arranque
y en el trabajo que no es etapa (validaciones, guardado del documento y armado de la respuesta con
los base64).
Variable del .env | Para qué |
|---|---|
MONITOR_SLOW_REQUEST_MS | Milisegundos a partir de los cuales se registra una petición. Por defecto 3000; 0 registra todas. |
MONITOR_TRACK_QUERIES | En false se siguen registrando las peticiones lentas, pero sin el detalle de consultas. |
MONITOR_RETENTION_DAYS | Días que se conservan los registros. Por defecto 7. |
3. Qué descartar antes de culpar al API
- Dónde está la base de datos. Una emisión lanza muchas consultas; lo que las convierte en
segundos es que cada una viaje lejos. Con la base en otro host, en Docker Desktop o detrás de
una VPN, el mismo trabajo puede costar segundos en lugar de décimas. Mírelo en
query_time_ms. - El correo. Para comprobar cuánto pesa, emita una factura con
"sendmail": false. - El almacenamiento S3. Con
storage_modeens3odual, cada documento sube sus archivos dentro de la petición. Se ve en la etapas3. - El ambiente de la DIAN. Habilitación responde más lento que producción, así que no compare una instalación en habilitación contra otra en producción.
- El límite de peticiones. El grupo
apiadmite 60 peticiones por minuto; en facturación masiva aparecen respuestas429y reintentos que se viven como lentitud. - Las tablas de auditoría.
logsguarda el cuerpo de cada llamada al API y no se purga sola. - Contenedores que no usa. El
docker composedel 2026 levanta también el programador de tareas y el worker del extractor (con Chrome). En un VPS pequeño le quitan CPU y memoria al API: si no usa el extractor, conviene no levantar ese servicio. pm.max_childrende php-fpm. Si es muy bajo, las emisiones se encolan.
config:cache ni route:cache todavíaEl proyecto aún lee algunos valores con env() en tiempo de ejecución y define rutas con
closures: con la configuración cacheada esas funciones se apagarían sin avisar. Después de
cambiar el .env ejecute únicamente php artisan config:clear.
4. Comparar con el API 2025
En el 2025 no existe el módulo de monitoreo, así que la comparación se hace sobre el tiempo total que reporta su software de facturación, emitiendo el mismo tipo de documento, con el mismo número de líneas y en el mismo ambiente de la DIAN.
El detalle completo del diagnóstico, con la comparación entre ambas versiones, está en esta guía.