Why systemd ExecStartPost Fails to Create PID File for Beanstalkd Service


5 views

When configuring beanstalkd as a systemd service, many developers encounter a puzzling situation where the ExecStartPost directive doesn't seem to execute as expected. The specific case involves attempting to create a PID file after the service starts:

[Service]
ExecStart=/usr/bin/beanstalkd
ExecStartPost=/bin/sh -c 'pgrep beanstalkd > /var/run/beanstalkd.pid'

The immediate thought might be that systemd isn't executing the post-start command, but the reality is more nuanced. Several factors could be at play:

  • Permission issues with the target directory (/var/run)
  • The timing of when the command executes relative to process startup
  • Shell interpretation differences in the command

Instead of relying on ExecStartPost, systemd provides built-in mechanisms for PID file handling:

[Service]
ExecStart=/usr/bin/beanstalkd -p /var/run/beanstalkd.pid
PIDFile=/var/run/beanstalkd.pid

If the service doesn't natively support PID file creation, consider this alternative approach:

[Service]
ExecStart=/usr/bin/beanstalkd
ExecStartPost=/bin/sh -c 'mainpid=$(systemctl show --property=MainPID --value %n) && echo $mainpid > /var/run/beanstalkd.pid'

When troubleshooting, these commands can reveal valuable information:

# Check service status with full output
systemctl status beanstalkd.service -l

# View the complete journal for the service
journalctl -u beanstalkd.service --no-pager

# Verify systemd's interpretation of the unit file
systemd-analyze verify /etc/systemd/system/beanstalkd.service

For services that don't maintain their own PID file, consider these solutions:

  1. Use Type=forking if the service supports traditional daemon behavior
  2. Implement a small wrapper script that handles PID file creation
  3. Use systemd's temporary file handling with RuntimeDirectory

Example wrapper script approach:

#!/bin/sh
/usr/bin/beanstalkd &
echo $! > /var/run/beanstalkd.pid

When configuring beanstalkd as a systemd service, many developers attempt to create a PID file using ExecStartPost like this:

[Service]
ExecStart=/usr/local/bin/beanstalkd 
ExecStartPost=pgrep beanstalkd > /var/run/beanstalkd.pid

Surprisingly, the PID file never gets created. Let's dive into why this happens and explore better solutions.

The main issues with this approach are:

  • ExecStartPost runs in the same environment as ExecStart, which might not have write permissions to /var/run
  • The command might execute before the process is fully initialized
  • Systemd doesn't show errors from ExecStartPost commands by default

Method 1: Use systemd's Built-in PID File Handling

The most reliable approach is to let systemd manage the PID file:

[Service]
ExecStart=/usr/local/bin/beanstalkd -p /var/run/beanstalkd.pid
PIDFile=/var/run/beanstalkd.pid

Method 2: Use Type=forking with PIDFile

If your service supports forking:

[Service]
Type=forking
ExecStart=/usr/local/bin/beanstalkd -b /var/run -p beanstalkd.pid
PIDFile=/var/run/beanstalkd.pid

Method 3: Alternative ExecStartPost Implementation

If you must use ExecStartPost, make it more robust:

[Service]
ExecStart=/usr/local/bin/beanstalkd
ExecStartPost=/bin/sh -c 'sleep 1; pgrep -f "/usr/local/bin/beanstalkd" > /var/run/beanstalkd.pid'

To troubleshoot ExecStartPost issues:

# Check service status
systemctl status beanstalkd

# View complete logs
journalctl -u beanstalkd -b

# Test the command manually
pgrep beanstalkd > /var/run/beanstalkd.pid
  • Always specify PIDFile in your unit file when possible
  • Use absolute paths for both the binary and PID file
  • Ensure proper permissions on the PID file directory
  • Consider using RuntimeDirectory for better isolation