feat: rework requireRestart to getActionOnUpdateTo to control restart/task-disruption behavior#19700
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds a new SupervisorSpec extension point to control whether supervisor restarts (stop+recreate) should gracefully stop managed tasks, enabling certain supervisor implementations to avoid disrupting running tasks during spec updates while preserving existing default behavior.
Changes:
- Added
SupervisorSpec#shouldRestartCauseTaskDisruption()with a default oftrueto preserve existing behavior. - Threaded the new flag through
SupervisorManagerso restarts can callSupervisor.stop(...)with either disruptive (true) or non-disruptive (false) behavior, while termination continues to always disrupt tasks.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
server/src/main/java/org/apache/druid/indexing/overlord/supervisor/SupervisorSpec.java |
Introduces the new default method used to decide whether restarts should disrupt managed tasks. |
indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/SupervisorManager.java |
Wires the new flag into supervisor restart/stop flows by passing it through to Supervisor.stop(...). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /** | ||
| * Returns true if the supervisor restart should cause task disruption, false otherwise | ||
| */ | ||
| default boolean shouldRestartCauseTaskDisruption() |
There was a problem hiding this comment.
Whether to restart tasks or not will depend on the difference between the current spec and proposed spec.
In some cases, we might want to rollover tasks and in other cases, we might want to continue with the existing tasks.
| default boolean shouldRestartCauseTaskDisruption() | |
| default boolean shouldRolloverTasksOnRestart(SupervisorSpec proposedSpec); |
| private SupervisorSpec possiblyStopAndRemoveSupervisorInternal( | ||
| String id, | ||
| boolean writeTombstone, | ||
| boolean shouldRestartCauseTaskDisruption |
There was a problem hiding this comment.
| boolean shouldRestartCauseTaskDisruption | |
| boolean terminateTasks |
|
@Fly-Style , since the methods The SupervisorAction getActionOnUpdateTo(SupervisorSpec proposedSpec);
enum SupervisorAction
{
NONE, RESTART_SUPERVISOR, RESTART_SUPERVISOR_AND_TASKS
}The advantage is that implementers would have to implement just one method and not need to worry about how the two methods play together. The end result would be much more intuitive. cc: @jtuglu1 , do you have any thoughts? |
FrankChen021
left a comment
There was a problem hiding this comment.
| Severity | Findings |
|---|---|
| P0 | 0 |
| P1 | 0 |
| P2 | 1 |
| P3 | 0 |
| Total | 1 |
Reviewed 2 of 2 changed files.
Found one lifecycle race where an active autoscaler can still disrupt tasks during an opted-out restart.
This is an automated review by Codex GPT-5.6-Sol
shouldRestartCauseTaskDisruption in SupervisorSpecshouldRolloverTasksOnRestart() in SupervisorSpec
| default boolean shouldRolloverTasksOnRestart(SupervisorSpec proposedSpec) | ||
| { |
There was a problem hiding this comment.
@Fly-Style , thinking some more on this, let's change the existing method requireRestart instead of adding a new method.
ref: #19700 (comment)
Let's try to merge it off soon so that we can ensure it is include it in Druid 38 to avoid multiple changes to this interface since it an extension API.
shouldRolloverTasksOnRestart() in SupervisorSpecrequireRestart to getActionOnUpdateTo to control restart/task-disruption behavior
kfaraz
left a comment
There was a problem hiding this comment.
Minor nitpicks, rest looks good!
| // Always stop/recreate, persisting whenever the spec actually changed (or is new). | ||
| final boolean specChanged = isSpecChangedAndValidated(spec); | ||
| final SupervisorSpec existingSpec = possiblyStopAndRemoveSupervisorInternal(spec.getId(), false); | ||
| final Pair<Supervisor, SupervisorSpec> current = supervisors.get(spec.getId()); |
There was a problem hiding this comment.
The skipRestartIfUnmodified flag is false by default.
So, in that case, I wonder if we shouldn't just retain current behaviour of always restarting the tasks.
There was a problem hiding this comment.
Meanwhile, we still may have it configured with only supervisor restart.
I am voting to have the update logic, not retain what we have now.
There was a problem hiding this comment.
Yeah, I was torn between the two options myself.
But then I realized the restart here really refers to the task restart itself, since that is where the churn happens. Restarting the supervisor itself is a cheap operation.
So when skipRestart is false, user doesn't want to skip restart at all, so we should restart both tasks and supervisors.
As for the default behaviour, we can update the default value of this flag in SupervisorResource in the next release (Druid 39).
|
@kfaraz all comments were addressed |
| { | ||
| private final boolean modified; | ||
| private final boolean restarted; | ||
| private final SupervisorSpecUpdateAction action; |
There was a problem hiding this comment.
Side thought: I wonder if this field will also get serialized out even though it doesn't have a getter.
|
Including this in Druid 38 to avoid unnecessary changes to the |
Today, updating a supervisor spec always restarts the supervisor and terminates its running tasks, even when the change is cosmetic. This makes routine spec updates unnecessarily disruptive to in-flight ingestion.
This PR replaces the boolean
SupervisorSpec#requireRestartwith a tri-stateSupervisorSpec#getActionOnUpdateTo(SupervisorSpec proposedSpec), returning aSupervisorSpecUpdateAction:NONE- persist the new spec, no restartRESTART_SUPERVISOR- restart the supervisor, but leave running tasks aloneRESTART_SUPERVISOR_AND_TASKS- restart the supervisor and terminate its tasks (previous behavior; still the default)