私は組み込みLinuxデバイスで動作するように設計されたWebベースのアプリケーションを開発しています。デバイスが起動したら、ノードサーバー(ローカルサービス)と2つの部分を起動する必要があります。ギアWebブラウザサーバーのURLを指します。ノードが起動して接続を受け入れるのに時間がかかるため(約8秒)、Webブラウザの実行が準備されるまで遅延する必要があります。。
systemdを使用することにしましたdbus サービスタイプこれを達成するためのアイデアは、ノードサーバーが完全に初期化されたときにdbus名を取得し、できるだけ早くWebブラウザを起動できるようにすることです。 dbusに名前でノードサーバー実装を登録し、server.node
次のようにノードサービス(server-node.service)を設定しました。
[Unit]
Description=starts node backend
[Service]
BusName=server.node
EnvironmentFile=/etc/server/server-node.conf
ExecStart=/usr/bin/node /opt/server/main.js 2>&1 | logger
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -2 $MAINPID
KillMode=process
Restart=on-failure
RestartSec=10s
[Install]
WantedBy=multi-user.target
Webブラウザのサービス(browser.service)は次のとおりです。
[Unit]
Description=starts cog web browser
Requires=server-node.service
After=server-node.sevice
[Service]
Type=simple
EnvironmentFile=/etc/server/cog.conf
#ExecStartPre=/bin/sleep 20
ExecStart=/usr/bin/cog http://localhost:3000/ui
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -2 $MAINPID
KillMode=process
Restart=on-failure
RestartSec=2s
[Install]
WantedBy=graphical-session.target
ここで問題はブラウザサービスは、ノードサービスが完全に有効になるまで待つことはできません。。systemctl start server-node.service
コマンドを実行すると時間がかかり(systemdがdbusに登録されるのを待っていることを意味します)、実行するとそのコマンドがステータスになっていることを示しますsystemctl status server-node.service
。activating
active
しかし、停止して実行するとsystemctl start browser.service
両方のサービスが起動しますが、ブラウザが最初から起動します。、サーバーにまだ接続できないため、HTTPエラーが表示されます。その行のコメントを外すと、ExecStartPre=
ブラウザを起動する前に20秒間スリープ状態になり、すべてがうまく機能しますが、ハードコーディングされた遅延を使用したくありません。
私も試しましたBindsTo=server-node.service
指示するしかし、同じことが起こります。
修正する
これはmain.ts
サーバーを初期化して使用する場所です。NestJsイベントフレームワーク:
async function bootstrap() {
// Prepare the environment
// .........
await app.listen(port, 'localhost').then(() => {
if (env === 'DEV') {
Logger.log(`| ${env} server listening on: http://localhost:${port} `);
} else {
Logger.log(`| ${env} server listening on port ${port} `);
}
// Grab the execution context to emit the app initialized event
// https://stackoverflow.com/a/53484892/1199132
app.get(EventEmitter2).emit('app.initialized');
});
}
bootstrap();
その後、dbus.service.ts
イベントがキャプチャされapp.initialized
処理されたときにdbusに名前を登録するには、次のようにします。dbus ネイティブライブラリ:
@OnEvent('app.initialized', { async: true })
register () {
Logger.log('Requesting dbus name ' + this.busName, this.constructor.name);
// Request the bus name
// See https://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-messages
this.bus.requestName(this.busName, 0, (err, name) => {
if (err) {
Logger.error('Error registering dbus name: ' + err, DbusService.name);
} else {
Logger.log('Registered dbus name with response: ' + name, DbusService.name);
}
});
}
dbus 名がリストされます。show system dbus nameを使用する場合busctl list
。
答え1
たぶんこれがあなたに必要なものかもしれません。次のようになります。
DBusシステムバスから名前を取得するサービスの場合は、Type = dbusを使用し、それに応じてBusName =を設定します。サービスはフォーク(デーモン化)してはいけません。システムバスから名前を取得すると、systemdはサービスが初期化されたと見なします。次の例は、一般的なDBusサービスを示しています。
[Unit]
Description=Simple DBus service
[Service]
Type=dbus
BusName=org.example.simple-dbus-service
ExecStart=/usr/sbin/simple-dbus-service
[Install]
WantedBy=multi-user.target
バスアクティベーション可能サービスの場合は、systemdサービスファイルに[Install]セクションを含めずに、対応するDBusサービスファイルにSystemdService =オプションを使用します(例:/usr/share/dbus-1/system-services/org)。 .yes .simple-dbus-service.service):
[D-BUS Service]
Name=org.example.simple-dbus-service
Exec=/usr/sbin/simple-dbus-service
User=root
SystemdService=simple-dbus-service.service
答え2
ExecStart=/usr/bin/node /opt/server/main.js 2>&1 |ロガー
たとえば、ここではシェル構文を使用できません。この2>&1 | logger
セクションは許可されません。
(stdoutとstderrがキャプチャされ、とにかく使用systemctl status
および/またはjournalctl
表示できるため、実際には必要ありません...)
ここでの問題は、ノードサービスが完全にアクティブになるのを待つブラウザサービスを実装できないことです。
これを行うには、接続を受け入れる準備ができたら、「セマフォファイル」/tmp/node.server.ready
(空の一般ファイルなど)を作成することをお勧めします。次に、このディレクティブを使用して、ファイルが生成されたときにブラウザユニットを起動するユニットを
作成します。*.path
望むより:Unit=browser.service
PathExists=/tmp/node.server.ready
man systemd.path
/tmp/node.server.ready
⚠️ノードサーバーを起動する前にノードサーバーが停止したら、もう一度このファイルを削除してください...
だからあなたは活性化のみルートユニットに引き寄せて準備ができたらアクティブにserver-node.service
なります。browser.service