closes 3286 wait for job remove signal youki-dev/youki #3299by cody-herbst $ man 5 org.freedesktop.systemd1

StartTransientUnit

With the D-Bus StartTransientUnit method, you can create and start a transient unit.

method
StartTransientUnit(in s name, in s mode, in a(sv) properties, in a(sa(sv)) aux, out o job)

Arguments:

  • name: the unit name to create
  • mode: start mode, same as StartUnit() (replace|fail|isolate|ignore-dependencies|ignore-requirements)
  • properties: list of unit properties
  • aux: list of auxiliary unit properties
  • job: object path of the created job

Waiting for job completion

Even if StartTransientUnit succeeds, the job is only queued and the unit is not fully started yet. So if you try to change properties right after calling StartTransientUnit, it can fail. To avoid this, you need to wait for job completion via signals. On systemd D-Bus, signals are not delivered unless you call Subscribe() first. Subscribe before starting the unit, and use the job object path returned by StartTransientUnit to identify the job safely.

You can monitor signals with busctl.

$ sudo busctl --system monitor org.freedesktop.systemd1
Example output
$ sudo busctl --system monitor org.freedesktop.systemd1
Monitoring bus message stream.
‣ Type=signal  Endian=l  Flags=1  Version=1 Cookie=1488314  Timestamp="Sat 2025-12-27 03:38:54.342384 UTC"
  Sender=:1.26174  Path=/org/freedesktop/systemd1  Interface=org.freedesktop.systemd1.Manager  Member=UnitNew
  UniqueName=:1.26174
  MESSAGE "so" {
          STRING "demo-youki-scope.scope";
          OBJECT_PATH "/org/freedesktop/systemd1/unit/demo_2dyouki_2dscope_2escope";
  };

‣ Type=signal  Endian=l  Flags=1  Version=1 Cookie=1488315  Timestamp="Sat 2025-12-27 03:38:54.342805 UTC"
  Sender=:1.26174  Path=/org/freedesktop/systemd1  Interface=org.freedesktop.systemd1.Manager  Member=JobNew
  UniqueName=:1.26174
  MESSAGE "uos" {
          UINT32 3725531;
          OBJECT_PATH "/org/freedesktop/systemd1/job/3725531";
          STRING "demo-youki-scope.scope";
  };

...

‣ Type=signal  Endian=l  Flags=1  Version=1 Cookie=1488322  Timestamp="Sat 2025-12-27 03:38:54.356210 UTC"
  Sender=:1.26174  Path=/org/freedesktop/systemd1  Interface=org.freedesktop.systemd1.Manager  Member=JobRemoved
  UniqueName=:1.26174
  MESSAGE "uoss" {
          UINT32 3725531;
          OBJECT_PATH "/org/freedesktop/systemd1/job/3725531";
          STRING "demo-youki-scope.scope";
          STRING "done";
  };

...

‣ Type=signal  Endian=l  Flags=1  Version=1 Cookie=1488327  Timestamp="Sat 2025-12-27 03:38:55.359587 UTC"
  Sender=:1.26174  Path=/org/freedesktop/systemd1  Interface=org.freedesktop.systemd1.Manager  Member=UnitRemoved
  UniqueName=:1.26174
  MESSAGE "so" {
          STRING "demo-youki-scope.scope";
          OBJECT_PATH "/org/freedesktop/systemd1/unit/demo_2dyouki_2dscope_2escope";
  };

Job completion is notified with the JobRemoved signal. The result can be failed as well, so check the string.

$ sudo busctl --system monitor --match "type='signal',sender='org.freedesktop.systemd1',interface='org.freedesktop.systemd1.Manager',member='JobRemoved'"

Monitoring bus message stream.
‣ Type=signal  Endian=l  Flags=1  Version=1 Cookie=1488427  Timestamp="Sat 2025-12-27 03:43:43.293516 UTC"
  Sender=:1.26174  Path=/org/freedesktop/systemd1  Interface=org.freedesktop.systemd1.Manager  Member=JobRemoved
  UniqueName=:1.26174
  MESSAGE "uoss" {
          UINT32 3725702;
          OBJECT_PATH "/org/freedesktop/systemd1/job/3725702";
          STRING "demo-youki-scope.scope";
          STRING "done";
  };
$ sudo systemd-run --scope --unit=demo-youki-scope sleep 1
Running as unit: demo-youki-scope.scope; invocation ID: 6a076f0e68724b9d9e0685bdd9e4e5c5

This was a good overview.
https://pythonhosted.org/txdbus/dbus_overview.html