Skip to content

Commit 7efe761

Browse files
committed
systemd: retry when the dbus connection returns EAGAIN
1 parent 6a793b6 commit 7efe761

File tree

2 files changed

+55
-3
lines changed

2 files changed

+55
-3
lines changed

systemd/dbus.go

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"math/rand/v2"
78
"sync"
9+
"time"
810

911
systemdDbus "github.com/coreos/go-systemd/v22/dbus"
1012
dbus "github.com/godbus/dbus/v5"
13+
"golang.org/x/sys/unix"
1114
)
1215

1316
var (
@@ -64,10 +67,34 @@ func (d *dbusConnManager) getConnection() (*systemdDbus.Conn, error) {
6467
}
6568

6669
func (d *dbusConnManager) newConnection() (*systemdDbus.Conn, error) {
67-
if dbusRootless {
68-
return newUserSystemdDbus()
70+
newDbusConn := func() (*systemdDbus.Conn, error) {
71+
if dbusRootless {
72+
return newUserSystemdDbus()
73+
}
74+
return systemdDbus.NewWithContext(context.TODO())
75+
}
76+
77+
var conn *systemdDbus.Conn
78+
var err error
79+
for retry := range 5 {
80+
conn, err = newDbusConn()
81+
if err == nil {
82+
break
83+
}
84+
if !errors.Is(err, unix.EAGAIN) {
85+
return nil, err
86+
}
87+
if retry < 4 {
88+
// Exponential backoff with jitter: base delay doubles each retry, plus random jitter up to 1 second
89+
baseDelay := time.Second << retry // 1s, 2s, 4s, 8s
90+
jitter := time.Duration(rand.IntN(1000)) * time.Millisecond
91+
time.Sleep(baseDelay + jitter)
92+
} else {
93+
// despite retries, still EAGAIN
94+
return nil, fmt.Errorf("dbus connection failed after 5 retries: %w", err)
95+
}
6996
}
70-
return systemdDbus.NewWithContext(context.TODO())
97+
return conn, nil
7198
}
7299

73100
// resetConnection resets the connection to its initial state

systemd/dbus_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package systemd
2+
3+
import (
4+
"sync"
5+
"testing"
6+
)
7+
8+
func Test200ParallelConnection(t *testing.T) {
9+
var dms []*dbusConnManager
10+
for range 400 {
11+
dms = append(dms, newDbusConnManager(false))
12+
}
13+
14+
var wg sync.WaitGroup
15+
for _, dm := range dms {
16+
wg.Add(1)
17+
go func(dm *dbusConnManager) {
18+
defer wg.Done()
19+
_, err := dm.newConnection()
20+
if err != nil {
21+
t.Error(err)
22+
}
23+
}(dm)
24+
}
25+
}

0 commit comments

Comments
 (0)