Make the TaskAction requeue duration configurable - #7770
Conversation
The controller requeued running TaskActions with a hardcoded 10s in eight places, so the responsiveness of task actions could not be tuned and neither could the reconcile load that comes with it. Add executor config requeueDuration, following the same shape as maxSystemFailures: a config field with a pflag tag, validation in setup.go, a field on TaskActionReconciler, and an accessor that falls back to TaskActionDefaultRequeueDuration when the field is unset. The default is unchanged at 10s, so existing deployments behave exactly as before. The cache reservation heartbeat is tied to the same value. It was a const aliased to the requeue duration, and it has to keep tracking it: a reservation lease shorter than the gap until the next reconcile would let another owner take the reservation while this TaskAction is still waiting. config_flags.go and config_flags_test.go are regenerated with pflags. Signed-off-by: stantheman0128 <stanshih888@gmail.com>
Three corrections after review of the previous commit. The pflags generator available here is pinned to flytestdlib v1.11.0, whose template still imports github.com/mitchellh/mapstructure. Running it reverted config_flags_test.go off go-viper/mapstructure/v2, which the rest of the tree moved to in flyteorg#7486, and it also emitted an unrelated maxConcurrentReconciles flag that main is missing. Keep only the requeueDuration output and leave both of those alone; the missing maxConcurrentReconciles flag is a separate pre-existing gap. The comment on the reservation lease overstated what it buys. The lease is a request: cache_service clamps it to its own maxReservationHeartbeat and expires the reservation after heartbeatGracePeriodMultiplier of the clamped value, 10s times 3 by default. Raising requeueDuration past that window without raising maxReservationHeartbeat too still leaves a gap. Say so in the code and in the config field docs instead of promising a guarantee that does not hold. Also document that 0 means the built-in default, which setup.go accepts silently while it rejects negatives. Signed-off-by: stantheman0128 <stanshih888@gmail.com>
There was a problem hiding this comment.
Pull request overview
This PR makes the TaskAction controller’s requeue interval configurable via executor config, replacing direct uses of the hard-coded TaskActionDefaultRequeueDuration (10s) with a reconciler-level accessor and plumbing that value through cache reservation heartbeats.
Changes:
- Add
requeueDurationto executor config/flags and validate it inexecutor/setup.go(reject negative values). - Plumb
RequeueDurationintoTaskActionReconcilerand user.requeueDuration()for requeue behavior across the controller. - Make the catalog reservation heartbeat track the requeue duration, with updated/added unit tests.
Reviewed changes
Copilot reviewed 5 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| executor/setup.go | Validates requeueDuration and wires it into the TaskAction reconciler. |
| executor/pkg/controller/taskaction_controller.go | Adds RequeueDuration and requeueDuration() accessor; switches requeue sites to use it. |
| executor/pkg/controller/taskaction_cache.go | Replaces fixed cache reservation heartbeat with one derived from the reconciler’s requeue duration and documents clamp behavior. |
| executor/pkg/controller/taskaction_cache_test.go | Updates existing heartbeat assertion and adds tests covering heartbeat tracking and default fallback behavior. |
| executor/pkg/config/config.go | Adds RequeueDuration to config with defaults and documentation. |
| executor/pkg/config/config_flags.go | Adds the requeueDuration flag wiring. |
| executor/pkg/config/config_flags_test.go | Adds generated-style flag decode test for requeueDuration. |
Files not reviewed (2)
- executor/pkg/config/config_flags.go: Generated file
- executor/pkg/config/config_flags_test.go: Generated file
Suppressed comments (1)
executor/pkg/controller/taskaction_controller.go:157
- The docstring for requeueDuration() says the cache reservation is held "at least until the next reconcile", but cache_service can clamp the requested heartbeat and expire the reservation after a grace-multiplier window. For larger requeue durations this guarantee does not hold, and the comment is misleading (the more detailed explanation in cacheReservationHeartbeat() is accurate).
// requeueDuration is how long to wait before reconciling a running TaskAction
// again. It also bounds the cache reservation heartbeat, so a serializable
// reservation is held at least until the next reconcile.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // RequeueDuration overrides how long to wait before reconciling a running | ||
| // TaskAction again. Zero means TaskActionDefaultRequeueDuration. | ||
| RequeueDuration time.Duration |
There was a problem hiding this comment.
Fixed in 5ef08ee. Both comments now say non-positive rather than zero.
The accessor comment on line 155 also still carried a stale claim about the reservation lease holding until the next reconcile. It now points at cacheReservationHeartbeat, which documents that cache_service clamps the requested heartbeat to its own maxReservationHeartbeat.
The field comment said zero means the default while the accessor treats any non-positive value that way, and the accessor comment still carried the reservation guarantee that was corrected in the previous commit. Point it at cacheReservationHeartbeat instead, which spells out the cache_service clamp. Signed-off-by: stantheman0128 <stanshih888@gmail.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 7 changed files in this pull request and generated no new comments.
Files not reviewed (2)
- executor/pkg/config/config_flags.go: Generated file
- executor/pkg/config/config_flags_test.go: Generated file
Suppressed comments (3)
executor/pkg/controller/taskaction_controller.go:107
- The RequeueDuration field comment says it only affects reconciling a running TaskAction, but this value is also used for retryable error paths (e.g. failing to build the task execution context) and other non-terminal retries. Updating the comment avoids a doc/behavior mismatch for operators and future maintainers.
// RequeueDuration overrides how long to wait before reconciling a running
// TaskAction again. Any non-positive value means TaskActionDefaultRequeueDuration.
RequeueDuration time.Duration
executor/pkg/config/config.go:107
- RequeueDuration is documented as only affecting "running" TaskActions, but the reconciler uses it for other retryable/non-terminal requeues as well (e.g. transient/system errors). Consider adjusting the doc comment and the pflag help string so they describe the actual behavior.
// RequeueDuration is how long the controller waits before reconciling a running
// TaskAction again. Lowering it makes task actions more responsive at the cost of
// more reconciles and more load on the plugin backends. 0 or unset means the
// built-in default of 10s.
executor/pkg/config/config_flags_test.go:329
- This generated flag test sets requeueDuration to the default value, so it doesn’t actually exercise parsing/decoding a non-default duration. Using a non-default (but valid) value here would better validate the new flag wiring.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 7 changed files in this pull request and generated no new comments.
Files not reviewed (2)
- executor/pkg/config/config_flags.go: Generated file
- executor/pkg/config/config_flags_test.go: Generated file
Tracking issue
Closes #7740
Why are the changes needed?
The TaskAction controller requeues running actions with
TaskActionDefaultRequeueDuration, a const 10s, referenced directly by eightRequeueAfter:sites. Operators cannot trade responsiveness against reconcile load without rebuilding the executor, which is what #7740 asks for.What changes were proposed in this pull request?
A new executor config field,
requeueDuration, shaped exactly like the existingmaxSystemFailures:config.goconfig.gosetup.gosetup.goTaskActionReconciler.MaxSystemFailuresTaskActionReconciler.RequeueDurationmaxSystemFailures()requeueDuration()The default stays 10s, so an executor that does not set the field behaves exactly as before.
The cache reservation heartbeat moves with it.
cacheReservationHeartbeatIntervalwas a const aliased to the requeue duration. It has to keep tracking it, because the reservation is only ever extended on the next reconcile: a lease shorter than the gap to that reconcile lets another owner take a serializable cache reservation while this TaskAction is still waiting.That said, the lease is a request, not a guarantee, and the code and config docs now say so.
cache_serviceclamps it inManager.resolvedHeartbeatto its ownmaxReservationHeartbeatand expires the reservation afterheartbeatGracePeriodMultiplierof the clamped value, 10s times 3 by default. RaisingrequeueDurationpast that window without also raisingmaxReservationHeartbeatstill leaves a gap. I chose to document that rather than silently promise a guarantee that does not hold, but if you would rather the executor refuse or warn on that combination, say so and I will add it.taskaction_condition.go'sRequeueAfter: time.Until(deadline)is deliberately untouched. That one wakes up at a timeout deadline rather than polling, so tying it to the poll interval would delay or miss the timeout.A note on the generated flags file
config_flags.goandconfig_flags_test.goare generated bypflags, and running the generator available in this tree produces two changes I did not include:config_flags_test.gofromgithub.com/go-viper/mapstructure/v2back togithub.com/mitchellh/mapstructure. The generator comes fromboilerplate/flyte/golang_support_tools, which pinsflytestdlib v1.11.0, and that version's template still emits the old import. Every otherconfig_flags_test.goin the tree moved to go-viper in feat(executor): configurable default service account for task pods #7486, so I kept the current import.maxConcurrentReconcilesflag. That field has a pflag tag inconfig.gobut no flag inconfig_flags.goon main, so the generator is right that something is missing, but it is a pre-existing gap unrelated to this change and I left it alone.So this diff contains only the generator's
requeueDurationoutput. Happy to split themaxConcurrentReconcilesgap into its own PR if that is useful. Worth flagging thatcheck-generaterunsmake bufand does not coverpflags, so neither of these would be caught by CI.How was this patch tested?
New unit tests:
TestRequeueDurationFallsBackToDefaultcovers unset, negative, and configured values, asserting bothrequeueDuration()andcacheReservationHeartbeat().TestHandleCacheBeforeExecutionReservationHeartbeatTracksRequeueDurationasserts the lease actually handed to the catalog follows a configured requeue duration.The second one is not tautological. Replacing
cacheReservationHeartbeat()with a fixed 10s turns it red:The existing assertion in
taskaction_cache_test.gowas updated toTaskActionDefaultRequeueDuration, since that reconciler leavesRequeueDurationunset and so exercises the fallback.Full
go test ./executor/..., compared against a cleanmaincheckout at the same commit:Both failures are identical on main and are environmental:
exec: "\usr\local\kubebuilder\bin\etcd": executable file not found. This machine has no envtest binaries.go build ./executor/...andgo vetare clean.Labels
Check all the applicable boxes
What was not tested
The envtest reconcile loop, for the reason above, so there is no end-to-end run of the controller with a raised
requeueDuration. The cross-service clamp described earlier is derived from readingManager.resolvedHeartbeatand thecache_servicedefaults, not from running two executors against one serializable cache key.This change was developed with AI assistance from Claude. I reviewed and verified it before submitting.