Repository navigation
perf: avoid rebuilding the eligible-worker snapshot per pending task in HttpRemoteTaskRunner #20299
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
base: master
Are you sure you want to change the base?
Changes from all commits
af69486
555a5d5
9b9c75e
c2daec7
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 |
|---|---|---|
|
|
@@ -46,6 +46,7 @@ | |
|
|
||
| import java.net.URL; | ||
| import java.util.ArrayList; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.concurrent.ConcurrentHashMap; | ||
|
|
@@ -77,6 +78,8 @@ public class WorkerHolder | |
| // Known list of tasks running/completed on this worker. | ||
| protected final AtomicReference<Map<String, TaskAnnouncement>> tasksSnapshotRef; | ||
|
|
||
| private final AtomicReference<ImmutableWorkerInfo> announcementsViewRef = new AtomicReference<>(); | ||
|
|
||
| private final AtomicReference<DateTime> lastCompletedTaskTime = new AtomicReference<>(DateTimes.nowUtc()); | ||
| private final AtomicReference<DateTime> blacklistedUntil = new AtomicReference<>(); | ||
| private final AtomicInteger continuouslyFailedTasksCount = new AtomicInteger(0); | ||
|
|
@@ -125,6 +128,7 @@ public WorkerHolder( | |
| knownAnnouncements.forEach(e -> announcements.put(e.getTaskId(), e)); | ||
| } | ||
| tasksSnapshotRef = new AtomicReference<>(announcements); | ||
| refreshAnnouncementsView(); | ||
| } | ||
|
|
||
| public Worker getWorker() | ||
|
|
@@ -149,12 +153,39 @@ public void setBlacklistedUntil(DateTime blacklistedUntil) | |
|
|
||
| public ImmutableWorkerInfo toImmutable() | ||
| { | ||
| return ImmutableWorkerInfo.fromWorkerAnnouncements( | ||
| final ImmutableWorkerInfo announcementsView = announcementsViewRef.get(); | ||
| return new ImmutableWorkerInfo( | ||
| getWorker(), | ||
| announcementsView.getCurrCapacityUsed(), | ||
| announcementsView.getCurrParallelIndexCapacityUsed(), | ||
| announcementsView.getCurrCapacityUsedByTaskType(), | ||
|
Member
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. [P2] Do not share the cached mutable task-type map Finding: This passes the cached view's task-type map directly into each returned ImmutableWorkerInfo. ImmutableWorkerInfo retains non-null maps as-is and exposes the map through getCurrCapacityUsedByTaskType(), so a caller that mutates a returned worker snapshot also mutates the cached view; subsequent snapshots and worker-selection decisions then see corrupted per-type counts. Before this cache, each toImmutable() call rebuilt an independent map. Suggestion: Publish an immutable copy of the task-type map in the cached view or copy it when constructing each returned worker snapshot.
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. Fair callout. fixed. toImmutable() now returns the task-type map wrapped in Collections.unmodifiableMap. Also covered by testToImmutableDoesNotExposeCachedCapacityByTaskType. |
||
| announcementsView.getAvailabilityGroups(), | ||
| announcementsView.getRunningTasks(), | ||
| lastCompletedTaskTime.get(), | ||
| blacklistedUntil.get() | ||
| ); | ||
| } | ||
|
|
||
| protected void refreshAnnouncementsView() | ||
| { | ||
| final ImmutableWorkerInfo view = ImmutableWorkerInfo.fromWorkerAnnouncements( | ||
| enabledWorker, | ||
| tasksSnapshotRef.get(), | ||
| lastCompletedTaskTime.get(), | ||
| blacklistedUntil.get() | ||
| ); | ||
| announcementsViewRef.set( | ||
| new ImmutableWorkerInfo( | ||
| view.getWorker(), | ||
| view.getCurrCapacityUsed(), | ||
| view.getCurrParallelIndexCapacityUsed(), | ||
| Collections.unmodifiableMap(view.getCurrCapacityUsedByTaskType()), | ||
| view.getAvailabilityGroups(), | ||
| view.getRunningTasks(), | ||
| view.getLastCompletedTaskTime(), | ||
| view.getBlacklistedUntil() | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| public int getContinuouslyFailedTasksCount() | ||
|
|
@@ -368,6 +399,7 @@ public void fullSync(List<WorkerHistoryItem> changes) | |
| } | ||
|
|
||
| tasksSnapshotRef.set(newSnapshot); | ||
| refreshAnnouncementsView(); | ||
|
|
||
| notifyListener(delta, isWorkerDisabled); | ||
| } | ||
|
|
@@ -419,6 +451,8 @@ public void deltaSync(List<WorkerHistoryItem> changes) | |
| } | ||
| } | ||
|
|
||
| refreshAnnouncementsView(); | ||
|
|
||
| notifyListener(delta, isWorkerDisabled); | ||
| } | ||
|
|
||
|
|
||
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.
[P1] Avoid deriving capacity from null-resource placeholders
Finding: When a worker rejoins while the runner still tracks a running task, HttpRemoteTaskRunner seeds this holder with a placeholder TaskAnnouncement whose TaskResource is null. Because the task is RUNNING, the eager refresh here passes it to ImmutableWorkerInfo.fromWorkerAnnouncements, which dereferences the resource to compute capacity and throws a NullPointerException during worker creation. The worker cannot rejoin and its task state cannot be reconciled.
Suggestion: Skip null-resource placeholder announcements when building the cached capacity view, or defer/otherwise guard this derivation until a real worker sync supplies complete task resources.
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.
This isn't possible. The
TaskAnnouncementconstructor has ->new TaskResource(taskId, 1)when the resource is null, so getTaskResource() is never null.Even then, I added testWorkerRejoiningWithPlaceholderAnnouncements