How do you use systemd to ensure remote database is available

@GracefulRestart's answer is the best if you only have one service depending on the availability of the database. However, if you have multiple services that have this requirement, make a oneshot service that all of the services can then have a Requires= dependency to:

/etc/systemd/system/[email protected]

[Unit]
Description=Checks database availability on %I
After=network.target
Requires=network.target

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/path/to/portopen.sh %I

[Install]
WantedBy=default.target

/path/to/portopen.sh

#!/bin/bash
dbhost=${1:-localhost}
dbport=${2:-5678}
maxtries=${3:-5}
wait=${4:-10}
tries=1

# Check communication to database
while ! [ 2>/dev/null : < /dev/tcp/$dbhost/$dbport ]; do
   echo "Unable to connect to database on $dbhost TCP/$dbport (attempt $tries): retrying in $wait seconds" >&2
   (( tries++ ))
   if [[ $tries -le $maxtries ]]; then
      sleep $wait
   else
      echo "Unable to connect to database on $dbhost TCP/$dbport: aborting"
      exit 1
   fi
done

I made the script a bit more flexible in case you change or add database servers, or the port changes, or you want to change the number of retries on a per-service level. If you don't need that, just call the service portopen.service and remove the %I parts.

Let's say your database server is on foobar and your database application runs on foobarapp.service. Make the following changes to foobarapp.service:

# systemctl edit foobarapp.service

[in editor]

[Unit]
[email protected]
[email protected]

Then reload systemd and start and enable the check:

# systemctl daemon-reload
# systemctl enable [email protected]

You can then restart foobarapp.service whenever you want. It should only start if [email protected] returns successfully.

If it doesn't already exist, the database application service foobarapp.service would then look like this:

/etc/systemd/system/foobarapp.service

[Unit]
Description=Foobar database application
# Add any other dependencies here
[email protected]
[email protected]

[Service]
# If it is a daemon, use "forking" instead
Type=simple
ExecStart=/path/to/exec

[Install]
WantedBy=default.target

Have you looked at ExecStartPre in the systemd service documentation?

I would suggest putting your database test in a script, have it use exit 0 on success and exit 1 on failure and then run it with ExecStartPre. You would then start your application using ExecStart.