Skip to content

Commit 5f46f65

Browse files
committed
feat: handle panics in goroutines
Wrap functions which run in goroutines so that their panics are recovered and turned into errors. Also, bump Go & some deps, rekres. Signed-off-by: Utku Ozdemir <utku.ozdemir@siderolabs.com>
1 parent d09ff45 commit 5f46f65

File tree

17 files changed

+172
-97
lines changed

17 files changed

+172
-97
lines changed

.github/workflows/lock.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
2+
#
3+
# Generated on 2025-06-09T15:23:45Z by kres 5c988d4.
4+
5+
name: Lock old issues
6+
"on":
7+
schedule:
8+
- cron: 0 2 * * *
9+
permissions:
10+
issues: write
11+
jobs:
12+
action:
13+
runs-on:
14+
- ubuntu-latest
15+
steps:
16+
- name: Lock old issues
17+
uses: dessant/lock-threads@v5.0.1
18+
with:
19+
issue-inactive-days: "60"
20+
log-output: "true"
21+
process-only: issues

.github/workflows/stale.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
2+
#
3+
# Generated on 2025-06-09T15:23:45Z by kres 5c988d4.
4+
5+
name: Close stale issues and PRs
6+
"on":
7+
schedule:
8+
- cron: 30 1 * * *
9+
permissions:
10+
issues: write
11+
pull-requests: write
12+
jobs:
13+
stale:
14+
runs-on:
15+
- ubuntu-latest
16+
steps:
17+
- name: Close stale issues and PRs
18+
uses: actions/stale@v9.1.0
19+
with:
20+
close-issue-message: This issue was closed because it has been stalled for 7 days with no activity.
21+
days-before-issue-close: "5"
22+
days-before-issue-stale: "180"
23+
days-before-pr-close: "-1"
24+
days-before-pr-stale: "45"
25+
operations-per-run: "2000"
26+
stale-issue-message: This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.
27+
stale-pr-message: This PR is stale because it has been open 45 days with no activity.

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
22
#
3-
# Generated on 2025-06-05T10:30:41Z by kres fc6afbe.
3+
# Generated on 2025-06-09T15:23:45Z by kres 5c988d4.
44

55
# common variables
66

@@ -21,12 +21,12 @@ PROTOBUF_GO_VERSION ?= 1.36.6
2121
GRPC_GO_VERSION ?= 1.5.1
2222
GRPC_GATEWAY_VERSION ?= 2.26.3
2323
VTPROTOBUF_VERSION ?= 0.6.0
24-
GOIMPORTS_VERSION ?= 0.33.0
24+
GOIMPORTS_VERSION ?= 0.34.0
2525
GOMOCK_VERSION ?= 0.5.2
2626
DEEPCOPY_VERSION ?= v0.5.6
2727
GOLANGCILINT_VERSION ?= v2.1.6
2828
GOFUMPT_VERSION ?= v0.8.0
29-
GO_VERSION ?= 1.24.3
29+
GO_VERSION ?= 1.24.4
3030
GO_BUILDFLAGS ?=
3131
GO_LDFLAGS ?=
3232
CGO_ENABLED ?= 0

go.mod

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
module github.com/siderolabs/siderolink
22

3-
go 1.23.0
3+
go 1.24.4
44

55
require (
66
github.com/google/uuid v1.6.0
77
github.com/jsimonetti/rtnetlink/v2 v2.0.2
88
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10
9-
github.com/siderolabs/gen v0.8.0
9+
github.com/siderolabs/gen v0.8.4
1010
github.com/siderolabs/go-pointer v1.0.0
1111
github.com/stretchr/testify v1.10.0
1212
go.uber.org/multierr v1.11.0
1313
go.uber.org/zap v1.27.0
1414
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
15-
golang.org/x/sync v0.10.0
16-
golang.org/x/sys v0.29.0
15+
golang.org/x/sync v0.15.0
16+
golang.org/x/sys v0.33.0
1717
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
1818
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10
1919
google.golang.org/grpc v1.69.4
@@ -29,10 +29,10 @@ require (
2929
github.com/mdlayher/netlink v1.7.2 // indirect
3030
github.com/mdlayher/socket v0.5.1 // indirect
3131
github.com/pmezard/go-difflib v1.0.0 // indirect
32-
golang.org/x/crypto v0.32.0 // indirect
32+
golang.org/x/crypto v0.39.0 // indirect
3333
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
34-
golang.org/x/net v0.34.0 // indirect
35-
golang.org/x/text v0.21.0 // indirect
34+
golang.org/x/net v0.41.0 // indirect
35+
golang.org/x/text v0.26.0 // indirect
3636
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
3737
google.golang.org/genproto/googleapis/rpc v0.0.0-20250122153221-138b5a5a4fd4 // indirect
3838
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect

go.sum

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgm
3636
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
3737
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
3838
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
39-
github.com/siderolabs/gen v0.8.0 h1:Pj93+hexkk5hQ7izjJ6YXnEWc8vlzOmDwFz13/VzS7o=
40-
github.com/siderolabs/gen v0.8.0/go.mod h1:an3a2Y53O7kUjnnK8Bfu3gewtvnIOu5RTU6HalFtXQQ=
39+
github.com/siderolabs/gen v0.8.4 h1:1Xj/YvKTXgpnr9ZC7heKcskJo5wHvWOybwjQSCfEmsQ=
40+
github.com/siderolabs/gen v0.8.4/go.mod h1:CRrktDXQf3yDJI7xKv+cDYhBbKdfd/YE16OpgcHoT9E=
4141
github.com/siderolabs/go-pointer v1.0.0 h1:6TshPKep2doDQJAAtHUuHWXbca8ZfyRySjSBT/4GsMU=
4242
github.com/siderolabs/go-pointer v1.0.0/go.mod h1:HTRFUNYa3R+k0FFKNv11zgkaCLzEkWVzoYZ433P3kHc=
4343
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
@@ -60,18 +60,18 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
6060
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
6161
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
6262
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
63-
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
64-
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
63+
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
64+
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
6565
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
6666
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
67-
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
68-
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
69-
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
70-
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
71-
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
72-
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
73-
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
74-
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
67+
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
68+
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
69+
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
70+
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
71+
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
72+
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
73+
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
74+
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
7575
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
7676
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
7777
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=

hack/siderolink-client/main.go

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"github.com/google/uuid"
2323
"github.com/siderolabs/gen/ensure"
24+
"github.com/siderolabs/gen/panicsafe"
2425
"github.com/siderolabs/gen/xslices"
2526
"github.com/siderolabs/go-pointer"
2627
"go.uber.org/zap"
@@ -83,7 +84,13 @@ func app() error {
8384
return fmt.Errorf("failed to create tunnel device: %w", err)
8485
}
8586

86-
go func() { cancel(device.Run()) }()
87+
go func() {
88+
if runErr := panicsafe.Run(func() {
89+
cancel(device.Run())
90+
}); runErr != nil {
91+
logger.Error("error running tunnel device", zap.Error(runErr))
92+
}
93+
}()
8794

8895
defer closeClosable(device.Close, "tunnel device", logger)
8996

@@ -102,13 +109,13 @@ func app() error {
102109
logger.Info("wireguard device link up", zap.String("interface", ifaceName))
103110

104111
go func() {
105-
monitorErr := monitorPeers(ctx, ctrl, ifaceName, logger)
106-
if monitorErr == nil {
107-
return
108-
}
112+
if monitorErr := panicsafe.RunErr(func() error {
113+
return monitorPeers(ctx, ctrl, ifaceName, logger)
114+
}); monitorErr != nil {
115+
logger.Error("peer monitoring failed", zap.Error(monitorErr))
109116

110-
logger.Error("peer monitoring failed", zap.Error(monitorErr))
111-
cancel(monitorErr)
117+
cancel(monitorErr)
118+
}
112119
}()
113120

114121
for {
@@ -202,7 +209,13 @@ func run(ctx context.Context, ctrl wgCtrl, ifaceName string, queuePair *wgbind.Q
202209

203210
defer closeClosable(relay.Close, "relay", logger)
204211

205-
go func() { cancel(relay.Run(ctx, logger)) }()
212+
go func() {
213+
if runErr := panicsafe.Run(func() {
214+
cancel(relay.Run(ctx, logger))
215+
}); runErr != nil {
216+
logger.Error("error running relay", zap.Error(runErr))
217+
}
218+
}()
206219

207220
for {
208221
select {
@@ -307,7 +320,10 @@ func notifyContextCause(ctx context.Context, sigs ...os.Signal) (context.Context
307320
}
308321

309322
func closeClosable(closeable func(), name string, logger *zap.Logger) {
310-
closeClosableErr(func() error { closeable(); return nil }, name, logger)
323+
closeClosableErr(func() error {
324+
closeable()
325+
return nil
326+
}, name, logger)
311327
}
312328

313329
func closeClosableErr(closeable func() error, name string, logger *zap.Logger) {
@@ -352,8 +368,8 @@ func provision(ctx context.Context, conn *grpc.ClientConn, key wgtypes.Key, clie
352368
}
353369

354370
type mxCtrl struct {
355-
mx sync.Mutex
356371
ctrl *wgctrl.Client
372+
mx sync.Mutex
357373
}
358374

359375
func (m *mxCtrl) ConfigureDevice(name string, cfg wgtypes.Config) error {

internal/wait/value_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func TestWaitableValue(t *testing.T) {
3232
require.True(t, ok)
3333
require.Equal(t, 42, value)
3434

35-
value, err := wv.Get(context.Background())
35+
value, err := wv.Get(t.Context())
3636
require.NoError(t, err)
3737
require.Equal(t, 42, value)
3838

@@ -60,7 +60,7 @@ func TestParallel(t *testing.T) { //nolint:tparallel
6060
t.Run("Get", func(t *testing.T) {
6161
t.Parallel()
6262

63-
val, err := wv.Get(context.Background())
63+
val, err := wv.Get(t.Context())
6464

6565
require.NoError(t, err)
6666
require.Equal(t, 42, val)
@@ -73,7 +73,7 @@ func TestParallel(t *testing.T) { //nolint:tparallel
7373
t.Run("Get", func(t *testing.T) {
7474
t.Parallel()
7575

76-
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
76+
ctx, cancel := context.WithTimeout(t.Context(), time.Millisecond)
7777
defer cancel()
7878

7979
val, err := wv.Get(ctx)
@@ -98,7 +98,7 @@ func TestTryGetSetUnset(t *testing.T) { //nolint:tparallel
9898

9999
var wv wait.Value[*int]
100100

101-
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
101+
ctx, cancel := context.WithTimeout(t.Context(), time.Second)
102102
t.Cleanup(cancel)
103103

104104
eg, ctx := errgroup.WithContext(ctx)

pkg/agent/event_sink.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"strings"
1313
"sync"
1414

15+
"github.com/siderolabs/gen/panicsafe"
1516
"golang.org/x/sync/errgroup"
1617
"google.golang.org/grpc"
1718
"gopkg.in/yaml.v3"
@@ -47,11 +48,11 @@ func eventSink(ctx context.Context, apiEndpoint string, eg *errgroup.Group) erro
4748

4849
stopServer := sync.OnceFunc(server.Stop)
4950

50-
eg.Go(func() error {
51+
eg.Go(panicsafe.RunErrF(func() error {
5152
defer stopServer()
5253

5354
return server.Serve(listen)
54-
})
55+
}))
5556

5657
context.AfterFunc(ctx, stopServer)
5758

pkg/agent/log_receiver.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"net/netip"
1313
"sync"
1414

15+
"github.com/siderolabs/gen/panicsafe"
1516
"go.uber.org/zap"
1617
"golang.org/x/sync/errgroup"
1718

@@ -34,7 +35,7 @@ func logReceiver(ctx context.Context, endpoint string, eg *errgroup.Group, logge
3435

3536
stopServer := sync.OnceFunc(srv.Stop)
3637

37-
eg.Go(func() error {
38+
eg.Go(panicsafe.RunErrF(func() error {
3839
defer stopServer()
3940

4041
serveErr := srv.Serve()
@@ -44,7 +45,7 @@ func logReceiver(ctx context.Context, endpoint string, eg *errgroup.Group, logge
4445
}
4546

4647
return serveErr
47-
})
48+
}))
4849

4950
context.AfterFunc(ctx, stopServer)
5051

pkg/agent/siderolink.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"sync"
1515
"time"
1616

17+
"github.com/siderolabs/gen/panicsafe"
1718
"go.uber.org/zap"
1819
"golang.org/x/sync/errgroup"
1920
"golang.zx2c4.com/wireguard/conn"
@@ -110,19 +111,19 @@ func sideroLink(ctx context.Context, eg *errgroup.Group, cfg sideroLinkConfig, p
110111
pb.RegisterProvisionServiceServer(s, srv)
111112
pb.RegisterWireGuardOverGRPCServiceServer(s, wggrpc.NewService(pt, allowedPeers, logger))
112113

113-
eg.Go(func() error {
114+
eg.Go(panicsafe.RunErrF(func() error {
114115
defer wgDevice.Close() //nolint:errcheck
115116

116117
return wgDevice.Run(ctx, logger, srv)
117-
})
118+
}))
118119

119120
stopServer := sync.OnceFunc(s.Stop)
120121

121-
eg.Go(func() error {
122+
eg.Go(panicsafe.RunErrF(func() error {
122123
defer stopServer()
123124

124125
return s.Serve(lis)
125-
})
126+
}))
126127

127128
context.AfterFunc(ctx, stopServer)
128129

0 commit comments

Comments
 (0)