Skip to content

Commit 0ed1a71

Browse files
authored
Retry NGINX provisioning on all errors (#4399)
Problem: Formerly, we would not retry provisioning if we got an error that a resource already exists. However, in certain cases, the timing was just right where back to back calls to CreateOrUpdate would result in the second call initially not finding the resource (as it was being created but didn't exist yet), and then when it decided to call Create, the resource now existed, and it would fail to update the resource to the new change. Solution: Retry the CreateOrUpdate call no matter what error is returned. This ensures that if we happen to hit this quick succession scenario, the second update call would eventually succeed and not fail immediately, after the CreateOrUpdate function determined that the resource does exist and simply needs an update, not a Create. Also added a return statement to safeguard against potential panics if an object is nil, due to a similar potential timing issue.
1 parent a1afc9d commit 0ed1a71

File tree

2 files changed

+17
-12
lines changed

2 files changed

+17
-12
lines changed

internal/controller/provisioner/provisioner.go

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package provisioner
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"slices"
78
"strings"
@@ -246,33 +247,35 @@ func (p *NginxProvisioner) provisionNginx(
246247
createCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
247248

248249
var res controllerutil.OperationResult
250+
var upsertErr error
249251
if err := wait.PollUntilContextCancel(
250252
createCtx,
251253
500*time.Millisecond,
252254
true, /* poll immediately */
253255
func(ctx context.Context) (bool, error) {
254-
var upsertErr error
255256
res, upsertErr = controllerutil.CreateOrUpdate(ctx, p.k8sClient, obj, objectSpecSetter(obj))
256257
if upsertErr != nil {
257-
if !apierrors.IsAlreadyExists(upsertErr) && !apierrors.IsConflict(upsertErr) {
258-
return false, upsertErr
259-
}
260-
if apierrors.IsConflict(upsertErr) {
261-
return false, nil
262-
}
258+
p.cfg.Logger.V(1).Info(
259+
"Retrying CreateOrUpdate for nginx resource after error",
260+
"namespace", gateway.GetNamespace(),
261+
"name", resourceName,
262+
"error", upsertErr.Error(),
263+
)
264+
return false, nil //nolint:nilerr // continue retrying
263265
}
264266
return true, nil
265267
},
266268
); err != nil {
269+
fullErr := errors.Join(err, upsertErr)
267270
p.cfg.EventRecorder.Eventf(
268271
obj,
269272
corev1.EventTypeWarning,
270273
"CreateOrUpdateFailed",
271274
"Failed to create or update nginx resource: %s",
272-
err.Error(),
275+
fullErr.Error(),
273276
)
274277
cancel()
275-
return err
278+
return fullErr
276279
}
277280
cancel()
278281

@@ -327,6 +330,10 @@ func (p *NginxProvisioner) provisionNginx(
327330
object = daemonSetObj
328331
}
329332

333+
if object == nil {
334+
return nil
335+
}
336+
330337
p.cfg.Logger.V(1).Info(
331338
"Restarting nginx after agent configmap update",
332339
"name", object.GetName(),

internal/controller/provisioner/setter.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,7 @@ func serviceSpecSetter(
119119
}
120120

121121
// Apply NGF-managed annotations (take precedence)
122-
for k, v := range objectMeta.Annotations {
123-
mergedAnnotations[k] = v
124-
}
122+
maps.Copy(mergedAnnotations, objectMeta.Annotations)
125123

126124
// Store current managed keys for next reconciliation
127125
if len(currentManagedKeys) > 0 {

0 commit comments

Comments
 (0)