Skip to content

Commit 7820c2b

Browse files
authored
Use single timeout for reload retries (#1128)
* Use single context for reload retries * Review feedback
1 parent 047ae0a commit 7820c2b

File tree

4 files changed

+164
-130
lines changed

4 files changed

+164
-130
lines changed

internal/mode/static/nginx/runtime/manager.go

+3-41
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package runtime
22

33
import (
4-
"bytes"
54
"context"
65
"errors"
76
"fmt"
@@ -18,7 +17,6 @@ import (
1817
const (
1918
pidFile = "/var/run/nginx/nginx.pid"
2019
pidFileTimeout = 10000 * time.Millisecond
21-
childProcsTimeout = 1000 * time.Millisecond
2220
nginxReloadTimeout = 60000 * time.Millisecond
2321
)
2422

@@ -27,11 +25,7 @@ type (
2725
checkFileFunc func(string) (fs.FileInfo, error)
2826
)
2927

30-
var (
31-
noNewWorkersErrFmt = "reload unsuccessful: no new NGINX worker processes started for config version %d." +
32-
" Please check the NGINX container logs for possible configuration issues: %w"
33-
childProcPathFmt = "/proc/%[1]v/task/%[1]v/children"
34-
)
28+
var childProcPathFmt = "/proc/%[1]v/task/%[1]v/children"
3529

3630
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . Manager
3731

@@ -83,18 +77,13 @@ func (m *ManagerImpl) Reload(ctx context.Context, configVersion int) error {
8377
return fmt.Errorf("failed to send the HUP signal to NGINX main: %w", err)
8478
}
8579

86-
if err := ensureNewNginxWorkers(
80+
if err = m.verifyClient.waitForCorrectVersion(
8781
ctx,
82+
configVersion,
8883
childProcFile,
8984
previousChildProcesses,
9085
os.ReadFile,
91-
childProcsTimeout,
9286
); err != nil {
93-
m.managerCollector.IncReloadErrors()
94-
return fmt.Errorf(noNewWorkersErrFmt, configVersion, err)
95-
}
96-
97-
if err = m.verifyClient.waitForCorrectVersion(ctx, configVersion); err != nil {
9887
m.managerCollector.IncReloadErrors()
9988
return err
10089
}
@@ -152,30 +141,3 @@ func findMainProcess(
152141

153142
return pid, nil
154143
}
155-
156-
func ensureNewNginxWorkers(
157-
ctx context.Context,
158-
childProcFile string,
159-
previousContents []byte,
160-
readFile readFileFunc,
161-
timeout time.Duration,
162-
) error {
163-
ctx, cancel := context.WithTimeout(ctx, timeout)
164-
defer cancel()
165-
166-
return wait.PollUntilContextCancel(
167-
ctx,
168-
25*time.Millisecond,
169-
true, /* poll immediately */
170-
func(ctx context.Context) (bool, error) {
171-
content, err := readFile(childProcFile)
172-
if err != nil {
173-
return false, err
174-
}
175-
if !bytes.Equal(previousContents, content) {
176-
return true, nil
177-
}
178-
return false, nil
179-
},
180-
)
181-
}

internal/mode/static/nginx/runtime/manager_test.go

-78
Original file line numberDiff line numberDiff line change
@@ -112,81 +112,3 @@ func TestFindMainProcess(t *testing.T) {
112112
})
113113
}
114114
}
115-
116-
func TestEnsureNewNginxWorkers(t *testing.T) {
117-
previousContents := []byte("1 2 3")
118-
newContents := []byte("4 5 6")
119-
120-
readFileError := func(string) ([]byte, error) {
121-
return nil, errors.New("error")
122-
}
123-
124-
readFilePrevious := func(string) ([]byte, error) {
125-
return previousContents, nil
126-
}
127-
128-
readFileNew := func(string) ([]byte, error) {
129-
return newContents, nil
130-
}
131-
132-
ctx := context.Background()
133-
cancellingCtx, cancel := context.WithCancel(ctx)
134-
time.AfterFunc(1*time.Millisecond, cancel)
135-
136-
tests := []struct {
137-
ctx context.Context
138-
readFile readFileFunc
139-
name string
140-
previousContents []byte
141-
expectError bool
142-
}{
143-
{
144-
ctx: ctx,
145-
readFile: readFileNew,
146-
previousContents: previousContents,
147-
expectError: false,
148-
name: "normal case",
149-
},
150-
{
151-
ctx: ctx,
152-
readFile: readFileError,
153-
previousContents: previousContents,
154-
expectError: true,
155-
name: "cannot read file",
156-
},
157-
{
158-
ctx: ctx,
159-
readFile: readFilePrevious,
160-
previousContents: previousContents,
161-
expectError: true,
162-
name: "no new workers",
163-
},
164-
{
165-
ctx: cancellingCtx,
166-
readFile: readFilePrevious,
167-
previousContents: previousContents,
168-
expectError: true,
169-
name: "context canceled",
170-
},
171-
}
172-
173-
for _, test := range tests {
174-
t.Run(test.name, func(t *testing.T) {
175-
g := NewWithT(t)
176-
177-
err := ensureNewNginxWorkers(
178-
test.ctx,
179-
"/childfile",
180-
test.previousContents,
181-
test.readFile,
182-
2*time.Millisecond,
183-
)
184-
185-
if test.expectError {
186-
g.Expect(err).To(HaveOccurred())
187-
} else {
188-
g.Expect(err).ToNot(HaveOccurred())
189-
}
190-
})
191-
}
192-
}

internal/mode/static/nginx/runtime/verify.go

+58-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package runtime
22

33
import (
4+
"bytes"
45
"context"
56
"errors"
67
"fmt"
@@ -15,6 +16,9 @@ import (
1516

1617
const configVersionURI = "/var/run/nginx/nginx-config-version.sock"
1718

19+
var noNewWorkersErrFmt = "reload unsuccessful: no new NGINX worker processes started for config version %d." +
20+
" Please check the NGINX container logs for possible configuration issues: %w"
21+
1822
// verifyClient is a client for verifying the config version.
1923
type verifyClient struct {
2024
client *http.Client
@@ -67,20 +71,29 @@ func (c *verifyClient) getConfigVersion() (int, error) {
6771
return v, nil
6872
}
6973

70-
// waitForCorrectVersion calls the config version endpoint until it gets the expectedVersion,
71-
// which ensures that a new worker process has been started for that config version.
72-
func (c *verifyClient) waitForCorrectVersion(ctx context.Context, expectedVersion int) error {
74+
// waitForCorrectVersion first ensures any new worker processes have been started, and then calls the config version
75+
// endpoint until it gets the expectedVersion, which ensures that a new worker process has been started for that config
76+
// version.
77+
func (c *verifyClient) waitForCorrectVersion(
78+
ctx context.Context,
79+
expectedVersion int,
80+
childProcFile string,
81+
previousChildProcesses []byte,
82+
readFile readFileFunc,
83+
) error {
7384
ctx, cancel := context.WithTimeout(ctx, c.timeout)
7485
defer cancel()
7586

76-
if err := wait.PollUntilContextCancel(
87+
if err := ensureNewNginxWorkers(
7788
ctx,
78-
25*time.Millisecond,
79-
true, /* poll immediately */
80-
func(ctx context.Context) (bool, error) {
81-
version, err := c.getConfigVersion()
82-
return version == expectedVersion, err
83-
}); err != nil {
89+
childProcFile,
90+
previousChildProcesses,
91+
readFile,
92+
); err != nil {
93+
return fmt.Errorf(noNewWorkersErrFmt, expectedVersion, err)
94+
}
95+
96+
if err := c.ensureConfigVersion(ctx, expectedVersion); err != nil {
8497
if errors.Is(err, context.DeadlineExceeded) {
8598
err = fmt.Errorf(
8699
"config version check didn't return expected version %d within the deadline",
@@ -91,3 +104,38 @@ func (c *verifyClient) waitForCorrectVersion(ctx context.Context, expectedVersio
91104
}
92105
return nil
93106
}
107+
108+
func (c *verifyClient) ensureConfigVersion(ctx context.Context, expectedVersion int) error {
109+
return wait.PollUntilContextCancel(
110+
ctx,
111+
25*time.Millisecond,
112+
true, /* poll immediately */
113+
func(ctx context.Context) (bool, error) {
114+
version, err := c.getConfigVersion()
115+
return version == expectedVersion, err
116+
},
117+
)
118+
}
119+
120+
func ensureNewNginxWorkers(
121+
ctx context.Context,
122+
childProcFile string,
123+
previousContents []byte,
124+
readFile readFileFunc,
125+
) error {
126+
return wait.PollUntilContextCancel(
127+
ctx,
128+
25*time.Millisecond,
129+
true, /* poll immediately */
130+
func(ctx context.Context) (bool, error) {
131+
content, err := readFile(childProcFile)
132+
if err != nil {
133+
return false, err
134+
}
135+
if !bytes.Equal(previousContents, content) {
136+
return true, nil
137+
}
138+
return false, nil
139+
},
140+
)
141+
}

0 commit comments

Comments
 (0)