Skip to main content
Most failures in FaPost are silent by nature. A provider that cannot reach you does not complain; a queue that is not being worked simply grows. Knowing where to look matters more than having alerts on everything.

Horizon

Queues are processed by Horizon, and its dashboard is the first place to look when messages arrive but nothing happens. Four supervisors run, grouped so that the latency-critical work is isolated: inbound processing and conversation replies share dedicated processes, while broadcasts, logging and background synchronisation are worked elsewhere. See Queues. In host tenancy mode the dashboard is served on the base domain and on declared platform subdomains only, never on a tenant’s host, and it stays closed until a user passes the viewHorizon gate; see Several tenants. What to watch:
  • Wait time on flow.execution — this is how long a contact waits before the assistant even begins. It should be near zero.
  • Failed jobs — a rising count on flow.execution means inbound messages are not being answered: replies are sent from inside that job.
  • Throughput on messaging.broadcast — expected to spike; it is the one queue whose depth is not alarming.
An installation without Horizon running accepts messages and never answers them. Everything looks healthy from the browser — the site serves, the panel works — because nothing about the web tier depends on the workers. See Services.

The scheduler

Four scheduled tasks matter, and all fail silently if the scheduler is not running: The monthly one is the trap: it fails at a month boundary, weeks after the scheduler stopped, and presents as flow logging breaking for no apparent reason.

Conversation retention

The conversation transcript is kept forever by default. To cap it, set CONVERSATION_RETENTION_DAYS in .env. The daily conversations:prune task then drops, in every tenant schema, the monthly conversation_messages partitions that lie wholly older than that many days. Whole months only, so a message lives between CONVERSATION_RETENTION_DAYS and about 31 days longer.
Pruning is irreversible. A dropped partition is gone for good; only a database backup brings it back. Preview first with php artisan conversations:prune --dry-run.
Conversation threads (the inbox rows and their metadata) and downloaded media are not touched. With the variable unset the task does nothing.

Webhook routing

Inbound routing resolves through Redis rather than the database, which makes the registry a cache with a source of truth behind it — and caches drift.
Reports and optionally repairs inconsistency between Redis and the database.
Rebuilds the registry from the database. Run it after a Redis flush, a restore, or a move to new Redis infrastructure — without it, channels exist and no message resolves.
Checks the ingress end to end: which driver is active, whether Redis is reachable, whether the key prefix matches, whether published specs agree with the adapters, and how many channels still point at a previous address. Run it first whenever webhooks are not arriving.

Per-assistant health

Each assistant console shows two counters that should stay boring: live sessions and errors in the last 24 hours. Live sessions climbing without traffic to explain it means conversations start and do not finish — usually a flow waiting at an input nobody answers. Errors above zero means at least one node failed; Flow logs says which.

Application logs

Laravel’s log carries application errors. Telescope is available in development and records every request with its contents — which is why it must be off in production.

Backpressure

Provider rate limits are handled preventively rather than as a reaction to being rejected. The relevant settings are per-tenant: message rate per chat, broadcast chunk size, and how hard the platform pushes when a provider strains. A provider complaining about rate is a signal to lower those, not to add retries — a retry storm against a limit is the same request made worse.