启动节点服务器,然后在启动时启动 systemd 中的 Web 浏览器 (Wayland)

启动节点服务器,然后在启动时启动 systemd 中的 Web 浏览器 (Wayland)

我正在开发一个基于 Web 的应用程序,旨在在嵌入式 Linux 设备中运行。设备启动时我需要启动两个部分:节点服务器(本地服务)和齿轮网络浏览器指向服务器 url。由于节点需要一段时间来启动和接受连接(大约8秒),我需要延迟网络浏览器的启动,直到它准备好

我决定使用systemddbus服务类型为了实现这一点,我们的想法是在节点服务器完全初始化时获取 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

这是网络浏览器的服务(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 名称已列出当使用显示系统 dbus 名称时busctl list

答案1

也许这就是您所需要的,如下:

DBus服务

对于在 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 .example.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 |记录器

您不能在这里使用 shell 语法,例如。该2>&1 | logger部分是不允许的。
(实际上不需要,因为 stdout 和 stderr 被捕获并可以使用systemctl status和/或journalctl无论如何查看......)

这里的问题是我无法实现浏览器服务来等待节点服务完全激活。

为此,我建议您在准备好接受连接时创建一个“信号量文件”,比如说/tmp/node.server.ready(只是一个空的常规文件)。然后,当使用该指令创建文件时,使用该指令
创建一个*.path启动浏览器单元的单元。 看:Unit=browser.servicePathExists=/tmp/node.server.ready
man systemd.path

  • ⚠️确保在启动节点服务器之前删除该/tmp/node.server.ready文件,并在节点服务器停止时再次删除...

这样你应该仅启用并使其拉入路径单元,当它准备好时,server-node.service路径单元又会激活......browser.service

相关内容