> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lekalao.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Processes

> Horizon, the scheduler and the SMTP relay: what has to keep running.

Besides the web server, Lekalao needs two processes, plus one that is optional.

## Horizon: the workers

Horizon works the queues. Three supervisors, one per queue:

| Queue     | Holds                                                     | Workers in production | Longest a job may run |
| --------- | --------------------------------------------------------- | --------------------- | --------------------- |
| `sending` | Every campaign and automation e-mail.                     | up to 10              | 150 s                 |
| `default` | Outgoing webhooks, the application's e-mails, short jobs. | 3                     | 300 s                 |
| `imports` | Contact imports and exports.                              | 2                     | 1 hour                |

Without Horizon, nothing goes out.

```ini /etc/systemd/system/lekalao-horizon.service theme={null}
[Unit]
Description=Lekalao Horizon
After=network.target redis-server.service postgresql.service

[Service]
User=lekalao
WorkingDirectory=/var/www/lekalao
ExecStart=/usr/bin/php artisan horizon
ExecStop=/usr/bin/php artisan horizon:terminate
Restart=always
RestartSec=5
KillSignal=SIGTERM
TimeoutStopSec=3600

[Install]
WantedBy=multi-user.target
```

```bash theme={null}
sudo systemctl enable --now lekalao-horizon
```

`TimeoutStopSec` lets an import in progress finish before the stop.

The dashboard is at `https://lekalao.example.com/horizon`, for **platform administrators** only.

<Note>
  To add sending workers, raise `maxProcesses` on the `sending` supervisor in
  `config/horizon.php`, then run `php artisan horizon:terminate`. The real
  rate is still capped by your providers and by the receiving mailboxes
  ([Sending safety](/deliverability/sending-safety)).
</Note>

## The scheduler

One cron line, for the `lekalao` user:

```cron theme={null}
* * * * * cd /var/www/lekalao && php artisan schedule:run >> /dev/null 2>&1
```

It sets off:

| How often        | Work                                                                                                                                                                                        |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Every minute     | Scheduled campaigns, statistics, A/B test winners, automations, the heartbeat.                                                                                                              |
| Every 10 minutes | Sends that got stuck are queued again.                                                                                                                                                      |
| Every hour       | RSS feeds.                                                                                                                                                                                  |
| Every night      | DNS check of the domains (2:30), deleting the unconfirmed (3:00), old exports (3:15) and old provider feedback (3:30), the purge (3:45), retention limits (4:15), engagement scores (4:30). |
| Every week       | List summaries (Monday 8:00), licence check (Tuesday 4:00).                                                                                                                                 |

The times are UTC. Every task is listed in [Commands](/self-hosting/commands).

<Tip>
  With Docker or a PaaS without cron, run `php artisan schedule:work` as one
  more process.
</Tip>

## The SMTP relay

Optional. So that software can send over SMTP through Lekalao ([SMTP relay](/developers/smtp-relay)):

```ini /etc/systemd/system/lekalao-smtp.service theme={null}
[Unit]
Description=Lekalao SMTP relay
After=network.target postgresql.service

[Service]
User=lekalao
WorkingDirectory=/var/www/lekalao
ExecStart=/usr/bin/php artisan lekalao:smtp --host=127.0.0.1 --port=2525 --hostname=smtp.lekalao.example.com
Restart=always

[Install]
WantedBy=multi-user.target
```

<Warning>
  The relay does not speak TLS, and it receives API tokens as passwords.
  Leave it on `127.0.0.1`, or put a TLS terminator in front of it (stunnel,
  HAProxy). Never expose it as it is on the internet.
</Warning>

So that **Settings → Documentation** tells the teams about it:

```dotenv .env theme={null}
LEKALAO_SMTP_ADVERTISE=true
LEKALAO_SMTP_HOST=smtp.lekalao.example.com
LEKALAO_SMTP_PORT=465
```

## After every deployment

Horizon keeps the old code in memory:

```bash theme={null}
php artisan horizon:terminate
```

systemd starts it again with the new one. Restart the SMTP relay too, when it runs.
