-
Notifications
You must be signed in to change notification settings - Fork 656
Scheduler/TaskReaper: handle unassigned tasks marked for shutdown #2574
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -251,7 +251,12 @@ func (tr *TaskReaper) tick() { | |
|
|
||
| runningTasks := 0 | ||
| for _, t := range historicTasks { | ||
| if t.DesiredState <= api.TaskStateRunning || t.Status.State <= api.TaskStateRunning { | ||
| // Skip tasks which are desired to be running but the current state | ||
| // is less than or equal to running. | ||
| // This check is important to ignore tasks which are running or need to be running, | ||
| // but to delete tasks which are either past running, | ||
| // or have not reached running but need to be shutdown (because of a service update, for example). | ||
| if t.DesiredState == api.TaskStateRunning && t.Status.State <= api.TaskStateRunning { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure this is really needed. Don't new tasks always start with desired state running?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure why you think this is not needed. We need to shutdown tasks with desired state SHUTDOWN and actual state < ASSIGNED. This condition is to skip tasks which are not those covered by the condition above. LMK if this is not clear and we can discuss IRL. @nishanttotla
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh oops, I missed the change from
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oops, I missed it too. This is needed, sorry for the sliip. |
||
| // Don't delete running tasks | ||
| runningTasks++ | ||
| continue | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -74,6 +74,12 @@ func (s *Scheduler) setupTasksList(tx store.ReadTx) error { | |
| continue | ||
| } | ||
|
|
||
| // Also ignore tasks that have not yet been assigned but desired state is beyond TaskStateRunning | ||
| // This can happen if you update, delete or scale down a service before its tasks were assigned. | ||
| if t.Status.State == api.TaskStatePending && t.DesiredState > api.TaskStateRunning { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this comparison not
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The < is already handled in the condition above @nishanttotla
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @anshulpundir sorry maybe I'm missing something, but for
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My bad, please ignore my comments. I got confused between two changes. |
||
| continue | ||
| } | ||
|
|
||
| s.allTasks[t.ID] = t | ||
| if t.NodeID == "" { | ||
| s.enqueue(t) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2277,6 +2277,94 @@ func TestPreassignedTasks(t *testing.T) { | |
| assert.Equal(t, assignment3.NodeID, "node2") | ||
| } | ||
|
|
||
| func TestIgnoreTasks(t *testing.T) { | ||
| ctx := context.Background() | ||
| initialNodeSet := []*api.Node{ | ||
| { | ||
| ID: "node1", | ||
| Spec: api.NodeSpec{ | ||
| Annotations: api.Annotations{ | ||
| Name: "name1", | ||
| }, | ||
| }, | ||
| Status: api.NodeStatus{ | ||
| State: api.NodeStatus_READY, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| // Tasks with desired state running, shutdown, remove. | ||
| initialTaskSet := []*api.Task{ | ||
| { | ||
| ID: "task1", | ||
| DesiredState: api.TaskStateRunning, | ||
| ServiceAnnotations: api.Annotations{ | ||
| Name: "name1", | ||
| }, | ||
|
|
||
| Status: api.TaskStatus{ | ||
| State: api.TaskStatePending, | ||
| }, | ||
| }, | ||
| { | ||
| ID: "task2", | ||
| DesiredState: api.TaskStateShutdown, | ||
| ServiceAnnotations: api.Annotations{ | ||
| Name: "name2", | ||
| }, | ||
| Status: api.TaskStatus{ | ||
| State: api.TaskStatePending, | ||
| }, | ||
| NodeID: initialNodeSet[0].ID, | ||
| }, | ||
| { | ||
| ID: "task3", | ||
| DesiredState: api.TaskStateRemove, | ||
| ServiceAnnotations: api.Annotations{ | ||
| Name: "name2", | ||
| }, | ||
| Status: api.TaskStatus{ | ||
| State: api.TaskStatePending, | ||
| }, | ||
| NodeID: initialNodeSet[0].ID, | ||
| }, | ||
| } | ||
|
|
||
| s := store.NewMemoryStore(nil) | ||
| assert.NotNil(t, s) | ||
| defer s.Close() | ||
|
|
||
| err := s.Update(func(tx store.Tx) error { | ||
| // Prepopulate nodes | ||
| for _, n := range initialNodeSet { | ||
| assert.NoError(t, store.CreateNode(tx, n)) | ||
| } | ||
|
|
||
| // Prepopulate tasks | ||
| for _, task := range initialTaskSet { | ||
| assert.NoError(t, store.CreateTask(tx, task)) | ||
| } | ||
| return nil | ||
| }) | ||
| assert.NoError(t, err) | ||
|
|
||
| scheduler := New(s) | ||
|
|
||
| watch, cancel := state.Watch(s.WatchQueue(), api.EventUpdateTask{}) | ||
| defer cancel() | ||
|
|
||
| go func() { | ||
| assert.NoError(t, scheduler.Run(ctx)) | ||
| }() | ||
|
|
||
| // task1 is the only task that gets assigned since other two tasks | ||
| // are ignored by the scheduler. | ||
| // Normally task2/task3 should get assigned first since its a preassigned task. | ||
| assignment3 := watchAssignment(t, watch) | ||
| assert.Equal(t, assignment3.ID, "task1") | ||
| assert.Equal(t, assignment3.NodeID, "node1") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we also assert here that task2/task3 are still in the same state? |
||
| } | ||
|
|
||
| func watchAssignmentFailure(t *testing.T, watch chan events.Event) *api.Task { | ||
| for { | ||
| select { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@anshulpundir sorry I don't follow why this is removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because desired state is api.TaskStateRunning when a task is created.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, makes sense.