go-systemd icon indicating copy to clipboard operation
go-systemd copied to clipboard

No asynchronous response when service is stopped

Open ndeubert opened this issue 2 years ago • 3 comments

I noticed when using this code:

func isChanged(prev *dbus.UnitStatus, curr *dbus.UnitStatus) bool {
	if prev.ActiveState != curr.ActiveState {
		return true
	}
	return false
}

func (o *Object) filterUnit(unit string) bool {
	if unit == o.cfg.PlatCfg.ServiceName1|| unit == o.cfg.PlatCfg.ServiceName2{
		return false
	}
	return true
}
...
o.asyncstatus, o.asyncerr = o.conn.SubscribeUnitsCustom(1*time.Second, 1, isChanged, o.filterUnit)

I do not get any events from the asyncstatus channel when the service is stopped in a terminal with sudo systemctl stop service1 like I do when I start a service with id, err := o.conn.StartUnitContext(o.ctx, svcName, "replace", o.async) or sudo systemctl start service1

Even if I stop the service programmatically with id, usererr := o.conn.StopUnitContext(o.ctx, o.cfg.PlatCfg.ServiceName1, "replace", o.async) I only see "done" on the async channel.

If I want to find out about these events do I need to use the dbus interface directly? Do I need to poll myself or use o.asyncstatus, o.asyncerr = o.conn.SubscribeUnits(1 * time.Second) and check if it goes away?. If I kill the process manually then I do get a "failed" event on the asyncstatus channel. I didn't see any mention of this being expected behavior in the documentation, but it seems odd not to be supported given the rest of the behavior. Thanks.

ndeubert avatar Feb 06 '23 01:02 ndeubert

I have same issue :(

	updates, errors := conn.SubscribeUnitsCustom(0, 10, isChanged, filterUnit)

	go func() {
		for err := range errors {
			log.Printf("Error: %s", err)
		}
	}()

	for update := range updates {
		for sName, status := range update {
			if status != nil {
				log.Printf("Service %s ActiveState changed to: %s\n", sName, status.ActiveState)
			} else {
				log.Printf("Service %s: no status\n", sName)
			}
		}
	}

log when I start/stop service many times:

2024/03/19 01:39:34 Service s-kek-1.service ActiveState changed to: active 2024/03/19 01:39:57 Service s-kek-1.service ActiveState changed to: deactivating 2024/03/19 01:39:57 Service s-kek-1.service: no status 2024/03/19 01:40:02 Service s-kek-1.service ActiveState changed to: active 2024/03/19 01:40:07 Service s-kek-1.service: no status 2024/03/19 01:40:12 Service s-kek-1.service ActiveState changed to: active

sometimes I see "deactivating" but always see "no status" when service stopped

BTW I see all logs in dbus monitor: dbus-monitor --system "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path='/org/freedesktop/systemd1/unit/s_2dkek_2d1_2eservice'" | awk '/string "ActiveState"/ { getline; print $0 }' terminal output:

         variant             string "active"
         variant             string "active"
         variant             string "deactivating"
         variant             string "inactive"
         variant             string "inactive"
         variant             string "inactive"
         variant             string "active"
         variant             string "active"
         variant             string "active"

vlw avatar Mar 18 '24 22:03 vlw

@ndeubert solution found!

package main

import (
	"fmt"
	"github.com/godbus/dbus/v5"
	"log"
	"strings"
)

func main() {
	conn, err := dbus.SystemBus()
	if err != nil {
		log.Fatalf("Failed to connect to System Bus: %v", err)
	}

	var rules = "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',arg0namespace='org.freedesktop.systemd1.Unit'"
	conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, rules)
	fmt.Println("Subscribed to PropertiesChanged signals for systemd units")

	c := make(chan *dbus.Signal, 10)
	conn.Signal(c)

	for v := range c {
		handleSignal(v)
	}
}

func handleSignal(v *dbus.Signal) {
	if len(v.Body) >= 3 {
		var unitPath dbus.ObjectPath
		var changedProps map[string]dbus.Variant
		//var iface string

		//iface = v.Body[0].(string)
		changedProps = v.Body[1].(map[string]dbus.Variant)
		unitPath = v.Path

		//fmt.Printf("Signal from interface %s for unit %s\n", iface, unitPath)

		for propName, propValue := range changedProps {
			if propName == "ActiveState" {
				//fmt.Println("ActiveState changed")
				unitName := strings.Replace(string(unitPath), "/org/freedesktop/systemd1/unit/", "", 1)
				unitName = strings.Replace(unitName, "_2e", ".", -1)
				unitName = strings.Replace(unitName, "_2d", "-", -1)
				unitName = strings.Replace(unitName, "_5f", "_", -1)
				fmt.Printf("Unit: %s, ActiveState: %s\n", unitName, propValue.Value().(string))
			}
		}
	}
}

Output:

Subscribed to PropertiesChanged signals for systemd units
Unit: php8.3-fpm.service, ActiveState: active
Unit: php8.3-fpm.service, ActiveState: active
Unit: php8.3-fpm.service, ActiveState: active
Unit: php8.3-fpm.service, ActiveState: active
Unit: php8.3-fpm.service, ActiveState: active
Unit: php8.3-fpm.service, ActiveState: active
Unit: user-1157.slice, ActiveState: inactive
Unit: user-1157.slice, ActiveState: active
Unit: user-runtime-dir_401157.service, ActiveState: inactive
Unit: user-runtime-dir_401157.service, ActiveState: activating
Unit: user-1157.slice, ActiveState: active
Unit: user-runtime-dir_401157.service, ActiveState: active
Unit: user-runtime-dir_401157.service, ActiveState: active
Unit: user_401157.service, ActiveState: inactive
Unit: user_401157.service, ActiveState: activating
Unit: user_401157.service, ActiveState: activating
Unit: user_401157.service, ActiveState: active
Unit: user_401157.service, ActiveState: active
Unit: user_401157.service, ActiveState: active
Unit: session-18886.scope, ActiveState: inactive
Unit: session-18886.scope, ActiveState: active
Unit: session-18886.scope, ActiveState: active
Unit: session-18886.scope, ActiveState: inactive
Unit: user-1158.slice, ActiveState: inactive
Unit: user-1158.slice, ActiveState: active
Unit: user-runtime-dir_401158.service, ActiveState: inactive
Unit: user-runtime-dir_401158.service, ActiveState: activating
Unit: user-1158.slice, ActiveState: active
Unit: user-runtime-dir_401158.service, ActiveState: active
Unit: user-runtime-dir_401158.service, ActiveState: active
Unit: user_401158.service, ActiveState: inactive

vlw avatar Mar 19 '24 00:03 vlw

Ah cool. thank you for following up

ndeubert avatar Mar 21 '24 13:03 ndeubert