01 / Deep-dive — Pipeline
Distributed
auto-publish
pipeline.
Un único job central que recorre todos los tenants, despacha trabajo a sus colas aisladas, y se reprograma a sí mismo cada minuto sin depender de cron externo. Fan-out masivo con invariantes estrictas.
- Angle
- Async · Scheduling · Fan-out
- Runtime
- Laravel Horizon · Redis · Supervisor
- Scope
- All tenants · 1 job · N integrations
- Cadence
- Self-rescheduling · 1 min tick
01
Flow.
Self-rescheduling fan-out
// architecture · fan-out tick
┌─────────────────────────┐
│ AutoPublishScheduler │ ◀─── self-dispatch delay(60s)
└──────────┬──────────────┘
│ dispatches
▼
┌─────────────────────────┐
│ ProcessAutoPublishPosts │ ← central-auto-publish queue
│ timeout 600s · 3x │ ← Horizon supervisor
└──────────┬──────────────┘
│ iterates
▼
┌─────────────────────────┐
│ for each tenant t: │
│ tenancy::init(t) │
│ select eligible() │
│ for each post p: │
│ provider.publish() │ ── external API ──▶ ●
│ post.markSent() │
└─────────────────────────┘
│
▼
┌─────────────────────────┐
│ Horizon dashboard │ ◀── metrics, failed jobs
│ storage/logs/*.log │ ◀── structured trace
└─────────────────────────┘ 02
Beats.
Six design decisions that matter
- 01
One job, every tenant
Un único job central —
ProcessAutoPublishPosts— itera sobre todos los tenants del sistema en cada ejecución. Para cada uno inicializa el contexto de tenancy (DB, cache, filesystem), consulta publicaciones conauto_publish = trueyestado = aprobado, y delega a la misma lógica de publicación que usa el flujo manual. Cero duplicación. - 02
Self-rescheduling — no external cron
El
AutoPublishSchedulerse auto-despacha cada 60 s usandodelay()de Laravel Queue. Al terminar su tick, encola su propia siguiente ejecución. Resultado: un sistema que se mantiene vivo solo — si Horizon corre, el pipeline corre. Sin cron externo, sin supervisión adicional. - 03
Queue isolation per tenant
QueueTenancyBootstrapperprefija las claves de Redis por tenant, así los workers procesan únicamente los jobs de su contexto. La colacentral-auto-publishvive en la DB central pero los jobs hijos ejecutan contra DBs de tenant — el bootstrapper intercala contextos sin colisión. - 04
Retry, timeout, memory — deterministic
Cada job declara explícitamente
timeout = 600s,tries = 3con backoff exponencial, ymemory = 512MB. El supervisorcentral-auto-publish-supervisorescala a 2 procesos en producción. Los fallos caen afailed_jobscon stack trace completo y dejan trazabilidad enstorage/logs/auto-publish.log. - 05
Strict selection invariants
La query de selección exige siete invariantes sobre cada publicación antes de tocar la API del proveedor:
auto_publish,estado,cuenta_id,fecha_publicacion_realnull,external_idnull, tipo de cuenta válido, y token del tenant verificado. Imposible re-publicar por accidente. - 06
Graceful provider failures
El provider externo falla — tokens expiran, rate-limits aparecen, APIs cambian payloads sin aviso. Cada publicación se encapsula en try/catch con clasificación del error: reintentable (red, 5xx) vs. terminal (4xx de negocio). Los terminales marcan el post como
errorcon mensaje humano-legible; los reintentables devuelven al job a la cola.
03
Signal.
Self-rescheduling in code
app/Jobs/AutoPublishScheduler.php
class AutoPublishScheduler implements ShouldQueue
{
public $timeout = 60;
public $tries = 3;
public function handle(): void
{
// 1. dispatch the work for this tick
ProcessAutoPublishPosts::dispatch()
->onQueue('central-auto-publish');
// 2. schedule our own next tick (60s later)
self::dispatch()->delay(now()->addMinute());
}
}
El patrón auto-dispatch elimina la dependencia de cron. Tras php artisan autopublish:start el sistema late solo mientras Horizon esté vivo — y Horizon tiene su propio supervisor, así que el loop se reinicia solo tras fallo.
04
Runtime.
Determinism at the edges
- Queue
- central-auto-publish · Redis
- Supervisor
- 2 procesos en prod · 1 en local
- Timeout
- 600 s por job
- Retries
- 3 con backoff exponencial
- Memory cap
- 512 MB por worker
- Tick cadence
- every minute · withoutOverlapping
05
Watch.
Observability
- Horizon dashboard
- Métricas en vivo: jobs por cola, throughput, failed jobs, supervisor health
- Structured logs
- Tenants procesados · publicaciones encontradas · errores por post · estadísticas finales
- Failed jobs table
- Stack traces completos con payload del job original — reintento con un comando
- Pail
- Tail en vivo de logs estructurados durante debugging