Skip to content

Commit c8756ea

Browse files
committed
feat!: simplify v1 API and harden cgroup detection
1 parent 6d12049 commit c8756ea

42 files changed

Lines changed: 2874 additions & 1147 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,23 @@
44
[![Go Report Card](https://goreportcard.com/badge/github.com/KimMachineGun/automemlimit)](https://goreportcard.com/report/github.com/KimMachineGun/automemlimit)
55
[![Test](https://github.com/KimMachineGun/automemlimit/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/KimMachineGun/automemlimit/actions/workflows/test.yml)
66

7-
Automatically set `GOMEMLIMIT` to match Linux [cgroups(7)](https://man7.org/linux/man-pages/man7/cgroups.7.html) memory limit.
7+
Automatically set `GOMEMLIMIT` based on the Linux [cgroups(7)](https://man7.org/linux/man-pages/man7/cgroups.7.html) memory limit.
88

99
See more details about `GOMEMLIMIT` [here](https://tip.golang.org/doc/gc-guide#Memory_limit).
1010

1111
## Notice
1212

13-
Version `v0.5.0` introduces a fallback to system memory limits as an experimental feature when cgroup limits are unavailable. Activate this by setting `AUTOMEMLIMIT_EXPERIMENT=system`.
14-
You can also use system memory limits via `memlimit.FromSystem` provider directly.
13+
Version `v1.0.0` simplifies the public API and improves cgroup memory limit detection.
1514

16-
This feature is under evaluation and might become a default or be removed based on user feedback.
17-
If you have any feedback about this feature, please open an issue.
15+
Key changes from v0.x:
16+
- `memlimit.Set` replaces `memlimit.SetGoMemLimitWithOpts`, `memlimit.SetGoMemLimit`, `memlimit.SetGoMemLimitWithProvider`, and `memlimit.SetGoMemLimitWithEnv`
17+
- `memlimit.Set` returns the previous `GOMEMLIMIT` instead of 0 when it skips configuration or returns an error
18+
- `memlimit.FromCgroup` replaces `memlimit.FromCgroupV1`, `memlimit.FromCgroupV2`, and `memlimit.FromCgroupHybrid`
19+
- `memlimit.WithEnv`, `AUTOMEMLIMIT_EXPERIMENT`, and `AUTOMEMLIMIT_DEBUG` were removed
20+
- `import _ "github.com/KimMachineGun/automemlimit"` now falls back to system memory by default
21+
- `memlimit.WithMin` sets a lower bound for `GOMEMLIMIT`
22+
- `memlimit.Set` now handles `memlimit.ErrNoLimit` by setting `GOMEMLIMIT` to `math.MaxInt64`
23+
- `memlimit.WithRefreshInterval` now requires a `context.Context` that can be canceled to stop the refresh goroutine
1824

1925
## Installation
2026

@@ -27,41 +33,34 @@ go get github.com/KimMachineGun/automemlimit@latest
2733
```go
2834
package main
2935

30-
// By default, it sets `GOMEMLIMIT` to 90% of cgroup's memory limit.
31-
// This is equivalent to `memlimit.SetGoMemLimitWithOpts(memlimit.WithLogger(slog.Default()))`
32-
// To disable logging, use `memlimit.SetGoMemLimitWithOpts` directly.
36+
// Importing this package sets GOMEMLIMIT automatically with system memory fallback enabled.
3337
import _ "github.com/KimMachineGun/automemlimit"
3438
```
3539

36-
or
40+
For more control, use `memlimit.Set` directly:
3741

3842
```go
3943
package main
4044

41-
import "github.com/KimMachineGun/automemlimit/memlimit"
45+
import (
46+
"log"
4247

43-
func init() {
44-
memlimit.SetGoMemLimitWithOpts(
45-
memlimit.WithRatio(0.9),
46-
memlimit.WithProvider(memlimit.FromCgroup),
47-
memlimit.WithLogger(slog.Default()),
48-
memlimit.WithRefreshInterval(1*time.Minute),
49-
)
50-
memlimit.SetGoMemLimitWithOpts(
48+
"github.com/KimMachineGun/automemlimit/memlimit"
49+
)
50+
51+
func main() {
52+
_, err := memlimit.Set(
5153
memlimit.WithRatio(0.9),
54+
memlimit.WithMin(100*1024*1024),
5255
memlimit.WithProvider(
5356
memlimit.ApplyFallback(
5457
memlimit.FromCgroup,
5558
memlimit.FromSystem,
5659
),
5760
),
58-
memlimit.WithRefreshInterval(1*time.Minute),
5961
)
60-
memlimit.SetGoMemLimit(0.9)
61-
memlimit.SetGoMemLimitWithProvider(memlimit.Limit(1024*1024), 0.9)
62-
memlimit.SetGoMemLimitWithProvider(memlimit.FromCgroup, 0.9)
63-
memlimit.SetGoMemLimitWithProvider(memlimit.FromCgroupV1, 0.9)
64-
memlimit.SetGoMemLimitWithProvider(memlimit.FromCgroupHybrid, 0.9)
65-
memlimit.SetGoMemLimitWithProvider(memlimit.FromCgroupV2, 0.9)
62+
if err != nil {
63+
log.Fatal(err)
64+
}
6665
}
6766
```

automemlimit.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// Package automemlimit sets GOMEMLIMIT automatically, falling back to system memory.
2+
//
3+
// import _ "github.com/KimMachineGun/automemlimit"
4+
//
5+
// Use the memlimit package directly for more control.
16
package automemlimit
27

38
import (
@@ -7,7 +12,13 @@ import (
712
)
813

914
func init() {
10-
memlimit.SetGoMemLimitWithOpts(
15+
memlimit.Set(
16+
memlimit.WithProvider(
17+
memlimit.ApplyFallback(
18+
memlimit.FromCgroup,
19+
memlimit.FromSystem,
20+
),
21+
),
1122
memlimit.WithLogger(slog.Default()),
1223
)
1324
}

examples/dynamic/main.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package main
22

33
import (
44
"bytes"
5+
"context"
56
"errors"
7+
"log"
68
"log/slog"
79
"os"
810
"os/signal"
@@ -12,27 +14,28 @@ import (
1214
"github.com/KimMachineGun/automemlimit/memlimit"
1315
)
1416

15-
func init() {
17+
func main() {
1618
slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stderr, nil)))
1719

18-
memlimit.SetGoMemLimitWithOpts(
20+
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
21+
defer stop()
22+
23+
_, err := memlimit.Set(
1924
memlimit.WithProvider(
20-
FileProvider("limit.txt"),
25+
fileProvider("limit.txt"),
2126
),
22-
memlimit.WithRefreshInterval(5*time.Second),
27+
memlimit.WithRefreshInterval(ctx, 5*time.Second),
2328
memlimit.WithLogger(slog.Default()),
2429
)
25-
}
26-
27-
func main() {
28-
c := make(chan os.Signal, 1)
29-
signal.Notify(c, os.Interrupt)
30+
if err != nil {
31+
log.Fatal(err)
32+
}
3033

31-
s := <-c
32-
slog.Info("signal captured", slog.Any("signal", s))
34+
<-ctx.Done()
35+
slog.Info("shutdown")
3336
}
3437

35-
func FileProvider(path string) memlimit.Provider {
38+
func fileProvider(path string) memlimit.Provider {
3639
return func() (uint64, error) {
3740
b, err := os.ReadFile(path)
3841
if err != nil {

examples/logger/main.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
package main
22

33
import (
4+
"log"
45
"log/slog"
56
"os"
67

78
"github.com/KimMachineGun/automemlimit/memlimit"
89
)
910

10-
func init() {
11-
memlimit.SetGoMemLimitWithOpts(
11+
func main() {
12+
_, err := memlimit.Set(
1213
memlimit.WithProvider(
1314
memlimit.Limit(1024*1024*1024),
1415
),
1516
memlimit.WithLogger(slog.New(slog.NewJSONHandler(os.Stderr, nil))),
1617
)
18+
if err != nil {
19+
log.Fatal(err)
20+
}
1721
}
18-
19-
func main() {}

examples/system/main.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
package main
22

33
import (
4+
"log"
5+
46
"github.com/KimMachineGun/automemlimit/memlimit"
57
)
68

7-
func init() {
8-
memlimit.SetGoMemLimitWithOpts(
9+
func main() {
10+
_, err := memlimit.Set(
911
memlimit.WithProvider(
1012
memlimit.ApplyFallback(
1113
memlimit.FromCgroup,
1214
memlimit.FromSystem,
1315
),
1416
),
1517
)
18+
if err != nil {
19+
log.Fatal(err)
20+
}
1621
}
17-
18-
func main() {}

0 commit comments

Comments
 (0)