web-dev-qa-db-ja.com

systemdを使用してリモートデータベースを確実に使用できるようにする方法

SysVでは、条件を使用して、データベースが稼働する前にアプリケーションが起動しないようにすることができます。私はinitスクリプトに待機する時間を与え、データベースサービスがまだ利用できない場合は、しばらくしてから最後にあきらめます。

start() {
local exec=/path/to/exec
local tries=1
[ -x $exec ] || exit 5
echo -n $"Starting $prog: "


#check communication to database
if ! [ 2>/dev/null : < /dev/tcp/$dbHost/$dbPort ]
    then
        while ! [ 2>/dev/null : < /dev/tcp/$dbHost/$dbPort ] && [ ! $tries -ge 5 ]
            do
                >&2 echo -e "Could not connect to the database on $dbHost\nWaiting 10 seconds to check database status, attempt $tries"
                sleep 10
                ((tries++))
        done
        sleep 10
        if ! (: < /dev/tcp/$dbHost/$dbPort ) 2>/dev/null
            then
                >&2 echo -e "Could not connect to the database on $dbHost aborting startup of $exec"
                exit 1
        fi
fi

私はドキュメントとグーグルで同様のシナリオを探していましたが、ローカルサービスを参照していないものは何も見つかりませんでした。

4
Michael Kelly

systemdサービスのドキュメントでExecStartPreを確認しましたか?

データベーステストをスクリプトに入れて、exit 0成功した場合、exit 1失敗した場合、ExecStartPreで実行します。次に、ExecStartを使用してアプリケーションを起動します。

2
GracefulRestart

@GracefulRestartの答えは、データベースの可用性に応じて1つのサービスしかない場合に最適です。ただし、この要件を持つサービスが複数ある場合は、すべてのサービスがRequires=依存関係を持つことができるワンショットサービスを作成します。

/ etc/systemd/system/portopen @ .service

[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

データベースサーバーを変更または追加したり、ポートを変更したり、サービスレベルでの再試行回数を変更したりする場合に備えて、スクリプトをもう少し柔軟にしました。それが必要ない場合は、サービスportopen.serviceを呼び出して%Iの部分を削除してください。

データベースサーバーがfoobar上にあり、データベースアプリケーションがfoobarapp.service上で実行されているとします。 foobarapp.serviceに次の変更を加えます。

# systemctl edit foobarapp.service

[エディタ内]

[Unit]
[email protected]
[email protected]

次に、systemdをリロードして、チェックを開始して有効にします。

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

その後、いつでもfoobarapp.serviceを再起動できます。 [email protected]が正常に戻った場合にのみ開始されます。

まだ存在しない場合、データベースアプリケーションサービスfoobarapp.serviceは次のようになります。

/ 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
3
ErikF