go-systemd
go-systemd copied to clipboard
No asynchronous response when service is stopped
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.
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"
@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
Ah cool. thank you for following up