SystemD

Running EmailEngine as a SystemD service

In most cases you probably do not want to run EmailEngine as a regular application but as a background service. Under Linux the easiest way to create such services would be with SystemD. EmailEngine does not fork itself and sends all it's logs to standard output so it's not a good match with SysV Init kind of system but it runs well with SystemD.

Prepare the App

First we need the application to be present. In this example we download the executable and place it under /opt directory. Why /opt, you say? Well, it's just as good as any other place, you could store it somewhere else.

$ wget https://github.com/postalsys/emailengine/releases/latest/download/emailengine.tar.gz
$ tar xzf emailengine.tar.gz
$ rm -rf emailengine.tar.gz
$ sudo mv emailengine /opt

Create service unit

All SystemD services require to have a valid service file. We can create one via the command line.

$ sudo vim /etc/systemd/system/emailengine.service

Once the editor is open, paste the following service file content into it and save it:

[Unit]
Description=EmailEngine
# Depending on how you installed Redis, it's service name might be different
After=redis

[Service]
# Configure environment variables
Environment="EENGINE_REDIS=redis://@127.0.0.1:6379/8"
Environment="EENGINE_PORT=3000"

# Folder where EmailEngine executable is located
WorkingDirectory=/opt

# EmailEngine does not require any special privileges
User=www-data
Group=www-data

# Run the EmailEngine executable
ExecStart=/opt/emailengine

Type=simple
Restart=always

SyslogIdentifier=emailengine

[Install]
WantedBy=multi-user.target

Now we can enable and start the service. Next time when we reboot our server, the service is started automatically.

$ sudo systemctl enable emailengine
$ sudo systemctl start emailengine

Verify that the service is running either by checking the service status or connecting to EmailEngine's port.

$ sudo systemctl status emailengine
● emailengine.service - EmailEngine
     Loaded: loaded (/etc/systemd/system/emailengine.service; disabled; vendor >
     Active: active (running) since Sat 2021-10-02 11:04:29 UTC; 1h 34min ago
   Main PID: 368410 (emailengine)
      Tasks: 17 (limit: 9284)
     Memory: 416.3M
     CGroup: /system.slice/emailengine.service
             └─368410 /opt/emailengine
...

$ curl 127.0.0.1:3000/metrics
# HELP thread_starts Number of started threads
# TYPE thread_starts counter
thread_starts 7
...

Checking output logs

When EmailEngine is installed as a SystemD service you can use standard SystemD tools for different tasks, also for logging.

For example to tail output from EmailEngine you can use the journalctl command:

$ journalctl -t emailengine -f

-- Logs begin at Tue 2021-06-01 12:53:14 UTC. --
Oct 02 12:43:43 srv-01 emailengine[369048]: {"level":30,"time":1633178623716,"pid":369048,"hostname":"srv-01","msg":"Starting EmailEngine","version":"1.14.5","node":"16.8.0"}
Oct 02 12:43:43 srv-01 emailengine[369048]: {"level":20,"time":1633178623716,"pid":369048,"hostname":"srv-01","msg":"IMAP Worker Count","workersImap":4}
Oct 02 12:43:43 srv-01 emailengine[369048]: {"level":20,"time":1633178623716,"pid":369048,"hostname":"srv-01","msg":"Webhooks Worker Count","workersWebhooks":1}
Oct 02 12:43:43 srv-01 emailengine[369048]: {"level":20,"time":1633178623717,"pid":369048,"hostname":"srv-01","msg":"Submission Worker Count","workersWebhooks":1}

This output is not very well readable but you can't directly use the log renderers shown here because of the metadata entries in front of EmailEngine output logs. These lines are not valid JSON, so the renderers would not be able to process these.

Luckily journalctl output can be modified, so we can ask it to drop all the metadata and only show log entries from EmailEngine. This way we can pipe that output to a log renderer of our choice.

$ journalctl -t emailengine -f -o cat | jq
{
  "level": 20,
  "time": 1633178713318,
  "pid": 369143,
  "hostname": "srv-01",
  "msg": "Webhooks Worker Count",
  "workersWebhooks": 1
}