Skip to content

Commit 87d6aae

Browse files
committed
fix: revert to per-resource watcher + increase FD limit in main.go
The shared watcher approach has fundamental issues: - Each fileREST instance starts a goroutine reading from the same Events channel - This causes event distribution conflicts between resources - Multiple resources adding the same directory causes issues Solution: 1. Revert to each resource having its own watcher 2. Increase file descriptor limit to 65535 in main.go init() 3. Add better error messages when watcher creation fails This ensures proper event isolation while providing enough FD headroom.
1 parent a67f011 commit 87d6aae

3 files changed

Lines changed: 39 additions & 15 deletions

File tree

src/apiserver/main.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,43 @@ limitations under the License.
1717
package main
1818

1919
import (
20+
"fmt"
2021
"os"
22+
"syscall"
2123

2224
"github.com/alibaba/higress/api-server/pkg/cmd/server"
2325
genericapiserver "k8s.io/apiserver/pkg/server"
2426
"k8s.io/component-base/cli"
2527
)
2628

29+
func init() {
30+
// Increase file descriptor limit early to avoid "too many open files" errors
31+
var rLimit syscall.Rlimit
32+
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil {
33+
fmt.Fprintf(os.Stderr, "Warning: failed to get rlimit: %v\n", err)
34+
return
35+
}
36+
37+
fmt.Printf("Current file descriptor limit: soft=%d hard=%d\n", rLimit.Cur, rLimit.Max)
38+
39+
// Try to set soft limit to 65535
40+
targetLimit := uint64(65535)
41+
if rLimit.Cur < targetLimit {
42+
rLimit.Cur = targetLimit
43+
// If hard limit is less than target, try to increase it (may require root)
44+
if rLimit.Max < targetLimit {
45+
rLimit.Max = targetLimit
46+
}
47+
48+
if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil {
49+
fmt.Fprintf(os.Stderr, "Warning: failed to set rlimit to %d: %v\n", targetLimit, err)
50+
return
51+
}
52+
53+
fmt.Printf("Updated file descriptor limit: soft=%d hard=%d\n", rLimit.Cur, rLimit.Max)
54+
}
55+
}
56+
2757
func main() {
2858
stopCh := genericapiserver.SetupSignalHandler()
2959
options := server.NewHigressServerOptions(os.Stdout, os.Stderr)

src/apiserver/pkg/apiserver/apiserver.go

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package apiserver
1919
import (
2020
"fmt"
2121

22-
"github.com/fsnotify/fsnotify"
2322
istiov1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3"
2423
admregv1 "k8s.io/api/admissionregistration/v1"
2524
authzv1 "k8s.io/api/authorization/v1"
@@ -170,15 +169,6 @@ func (c completedConfig) New() (*HigressServer, error) {
170169
}
171170
}
172171

173-
// Create shared watcher for file storage mode to avoid "too many open files"
174-
var sharedWatcher *fsnotify.Watcher
175-
if storageMode == options.Storage_File {
176-
sharedWatcher, err = fsnotify.NewWatcher()
177-
if err != nil {
178-
return nil, fmt.Errorf("failed to create shared file watcher: %v", err)
179-
}
180-
}
181-
182172
storageCreateFunc := func(
183173
groupResource schema.GroupResource,
184174
runtimeCodec runtime.Codec,
@@ -195,7 +185,7 @@ func (c completedConfig) New() (*HigressServer, error) {
195185
switch storageMode {
196186
case options.Storage_File:
197187
runtimeCodec = codec.NewFlatAwareCodec(groupResource, runtimeCodec)
198-
return registry.NewFileREST(groupResource, runtimeCodec, storageOptions.FileOptions.RootDir, extension, isNamespaced, singularName, newFunc, newListFunc, attrFunc, sharedWatcher)
188+
return registry.NewFileREST(groupResource, runtimeCodec, storageOptions.FileOptions.RootDir, extension, isNamespaced, singularName, newFunc, newListFunc, attrFunc)
199189
case options.Storage_Nacos:
200190
var encryptionKey []byte = nil
201191
if sensitive {

src/apiserver/pkg/registry/file_rest.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ func NewFileREST(
5454
newFunc func() runtime.Object,
5555
newListFunc func() runtime.Object,
5656
attrFunc storage.AttrFunc,
57-
sharedWatcher *fsnotify.Watcher,
5857
) (REST, error) {
5958
if attrFunc == nil {
6059
if isNamespaced {
@@ -63,6 +62,10 @@ func NewFileREST(
6362
attrFunc = storage.DefaultClusterScopedAttr
6463
}
6564
}
65+
watcher, err := fsnotify.NewWatcher()
66+
if err != nil {
67+
return nil, fmt.Errorf("failed to create file watcher for %s: %v", groupResource.Resource, err)
68+
}
6669
// file REST
6770
f := &fileREST{
6871
TableConvertor: rest.NewDefaultTableConvertor(groupResource),
@@ -75,7 +78,7 @@ func NewFileREST(
7578
newFunc: newFunc,
7679
newListFunc: newListFunc,
7780
attrFunc: attrFunc,
78-
dirWatcher: sharedWatcher,
81+
dirWatcher: watcher,
7982
fileWatchers: make(map[string]*fileWatch, 10),
8083
}
8184
if err := f.startDirWatcher(); err != nil {
@@ -111,8 +114,9 @@ func (f *fileREST) GetSingularName() string {
111114
}
112115

113116
func (f *fileREST) Destroy() {
114-
// Don't close the watcher as it's shared across all fileREST instances
115-
// The watcher will be closed when the server shuts down
117+
if f.dirWatcher != nil {
118+
_ = f.dirWatcher.Close()
119+
}
116120
}
117121

118122
func (f *fileREST) startDirWatcher() error {

0 commit comments

Comments
 (0)