web-dev-qa-db-ja.com

systemctl起動待ち

トラフィックサーバー をインストールしてセットアップするスクリプトがあります。

yum install -y trafficserver
systemctl start trafficserver

traffic_line -s proxy.config.url_remap.remap_required -v 0
traffic_line -s proxy.config.reverse_proxy.enabled -v 0

問題は、traffic_lineが次のエラーで失敗することです。

[接続]エラー(main_socket_fd 3):そのようなファイルまたはディレクトリエラーはありません:管理ポートに接続できませんでした。traffic_managerが実行されていることを確認してください

これは、トラフィックサーバーが実際に起動するのを待たずに、systemctl startがすぐに戻るためです。

systemctl startに、サービスが開始された後にのみ戻るように指示する方法はありますか?

これが不可能な場合、systemctl startの後に実行して、サービスが開始されるのを実際に待機できるコマンドはありますか?

3
Benjamin

これは、トラフィックサーバーが実際に起動するのを待たずに、_systemctl start_がすぐに戻るためです。

_systemctl start_に、サービスが開始された後にのみ戻るように指示する方法はありますか?

_systemctl start_doesサービスの準備ができるまで待機します(_--no-block_で呼び出された場合を除く)、サービスはそれを示す必要があるだけです適切に(つまり、_Type=simple_を使用しないでください)。サービスが準備が整ったときにsystemdに通知しない場合、_systemctl is-active_、_systemctl show_などのバリエーションは役立ちません。

コメントで述べたように、最もエレガントな解決策は、ソケットユニットです。 systemdがソケットを開始し、_traffic_line_がソケットに接続し、systemdがサービスを開始し、_traffic_line_がサービスがsystemdから継承したファイル記述子の接続の受け入れを開始するまでブロックします。

または、_Type=forking_(サービスがフォークされ、フォークされたサービスの準備ができるとメインPIDが終了します)または_Type=notify_(サービスが準備ができるとsd_notify(0, "READY=1")を呼び出します)を使用できます。

残念ながら、これらのソリューションはすべて、trafficserverからのサポートが必要です。独自のソケットを割り当てる代わりにsystemdのソケットを使用し、フォークしてメインプロセスで適切に待機するか、_sd_notify_を呼び出します。サーバーが連携していない場合、systemdはサーバーの準備ができている時期を魔法のように推測できません。:)


trafficserverのソースコードを少し見たところ、実際には_Type=forking_をサポートしている可能性があります。サーバーは、専用の_traffic_cop_コマンドによって起動され、サーバーが起動するまで待機しているようです。そして、いくつかの基本的なテストを実行します(少なくともコードはそのように見えます)。したがって、サービスの種類を変更すると、うまくいく場合があります。

_# /etc/systemd/system/trafficserver.service.d/type-forking.conf
[Service]
Type=forking
_
7

何度か試してみましたが、ようやく動作しました。

最初の試み

Systemctlのヘルプを調べたところ、is-activeコマンドが見つかりました。

$ systemctl is-active trafficserver
active

したがって、サービスがアクティブになるまで待機するシェルスクリプトを作成しました。

while true; do
    if [ $(systemctl is-active trafficserver) == "active" ]; then
        break
    fi

    sleep 1
done

残念ながら、開始/停止でテストすると、このスクリプトは期待どおりに機能しますが、その直後にtraffic_lineコマンドを実行するとまだ同じエラーが発生していました。実際のプロセスが完全に開始する前に(おそらく数ミリ秒)、サービスがアクティブであると報告されていると思います。

2回目の試み

だから私は別の方法を試しました。これがサービスの最初の開始であることを知っているので、trafficserverマネージャーのPIDファイルが存在するまで待つことができます。これが私が試したものです:

while [ ! -f /run/trafficserver/manager.lock ]; do
  sleep 1
done

同じ問題:trafficserverマネージャーのPIDファイルが書き込まれるとき、マネージャーは実際にはまだ注文を受け取る準備ができていないので、まだエラーが発生していますです。

くそー、私はブラインドを使いたくないsleep

3回目の試み

そのため、traffic_lineコマンド自体が失敗しないことを確認することにしました。

while ! traffic_line --status &> /dev/null; do
    sleep 1
done

そしてこれでうまくいく!

いいけど...

残念ながら、答えは私が使用しているサービス(trafficserver)に非常に固有のものであり、他のサービスには直接適用されません。

この質問に対するより一般的な答えを知っている場合は、遠慮なく共有してください。

3
Benjamin

私はシェルスクリプトが苦手ですが、ActiveStateSubStateの両方をテストしたいと思いますactiveおよびrunningをそれぞれ返す場合のプロパティ。

$ systemctl show trafficserver -p SubState,ActiveState
ActiveState=active
SubState=running

その後、スクリプトの2番目の部分を実行できるはずです。

1
Daniel

最も簡単な方法は、スクリプトにスリープを追加することです。

sleep 30

または ここ としてジョブ制御を行うことができます

0
Simon Greenwood