-
Notifications
You must be signed in to change notification settings - Fork 188
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
Better exposure of LB status in UI #2071
Changes from 4 commits
11d9475
7f6d885
8d7ab16
b568602
48852d5
46eec76
41e478b
e696de8
9ae61f5
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 |
---|---|---|
|
@@ -364,24 +364,6 @@ public List<SingularityTaskId> getAllTaskIds() { | |
return getChildrenAsIdsForParents("getAllTaskIds", paths, taskIdTranscoder); | ||
} | ||
|
||
private List<SingularityTaskId> getTaskIds(String root) { | ||
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. were these methods unused? 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. yeah all unused |
||
return getChildrenAsIds(root, taskIdTranscoder); | ||
} | ||
|
||
public List<String> getActiveTaskIdsAsStrings() { | ||
if (leaderCache.active()) { | ||
return leaderCache.getActiveTaskIdsAsStrings(); | ||
} | ||
|
||
List<String> results = new ArrayList<>(); | ||
|
||
for (String requestId : getChildren(LAST_ACTIVE_TASK_STATUSES_PATH_ROOT)) { | ||
results.addAll(getChildren(getLastActiveTaskParent(requestId))); | ||
} | ||
|
||
return results; | ||
} | ||
|
||
public List<SingularityTaskId> getActiveTaskIds() { | ||
return getActiveTaskIds(false); | ||
} | ||
|
@@ -836,6 +818,14 @@ public Optional<SingularityLoadBalancerUpdate> getLoadBalancerState(SingularityT | |
return getData(getLoadBalancerStatePath(taskId, requestType), taskLoadBalancerUpdateTranscoder); | ||
} | ||
|
||
public boolean isInLoadBalancer(SingularityTaskId taskId) { | ||
if (exists(getLoadBalancerStatePath(taskId, LoadBalancerRequestType.REMOVE))) { | ||
return false; | ||
} | ||
return exists(getLoadBalancerStatePath(taskId, LoadBalancerRequestType.ADD)) | ||
|| exists(getLoadBalancerStatePath(taskId, LoadBalancerRequestType.DEPLOY)); | ||
} | ||
|
||
public Optional<SingularityPendingTask> getPendingTask(SingularityPendingTaskId pendingTaskId) { | ||
if (leaderCache.active()) { | ||
return leaderCache.getPendingTask(pendingTaskId); | ||
|
@@ -1025,6 +1015,13 @@ public SingularityCreateResult saveKilledRecord(SingularityKilledTaskIdRecord ki | |
return save(getKilledPath(killedTaskIdRecord.getTaskId()), killedTaskIdRecord, killedTaskIdRecordTranscoder); | ||
} | ||
|
||
public boolean isKilledTask(SingularityTaskId taskId) { | ||
if (leaderCache.active()) { | ||
return leaderCache.getKilledTaskRecord(taskId).isPresent(); | ||
} | ||
return exists(getKilledPath(taskId)); | ||
} | ||
|
||
public List<SingularityKilledTaskIdRecord> getKilledTaskIdRecords() { | ||
if (leaderCache.active()) { | ||
return leaderCache.getKilledTasks(); | ||
|
@@ -1183,10 +1180,6 @@ public void purgeStaleRequests(List<String> activeRequestIds, long deleteBeforeT | |
} | ||
} | ||
|
||
public SingularityDeleteResult deleteRequestId(String requestId) { | ||
return delete(getRequestPath(requestId)); | ||
} | ||
|
||
public long getTaskStatusBytes() { | ||
return countBytes(getChildren(LAST_ACTIVE_TASK_STATUSES_PATH_ROOT)); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,9 +9,6 @@ | |
import java.util.concurrent.CompletableFuture; | ||
import java.util.stream.Collectors; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import com.google.inject.Inject; | ||
import com.google.inject.Singleton; | ||
import com.hubspot.mesos.JavaUtils; | ||
|
@@ -41,7 +38,6 @@ | |
import com.hubspot.singularity.data.SingularityValidator; | ||
import com.hubspot.singularity.data.TaskManager; | ||
import com.hubspot.singularity.data.UserManager; | ||
import com.hubspot.singularity.data.history.TaskHistoryHelper; | ||
import com.hubspot.singularity.expiring.SingularityExpiringBounce; | ||
import com.hubspot.singularity.expiring.SingularityExpiringPause; | ||
import com.hubspot.singularity.expiring.SingularityExpiringScale; | ||
|
@@ -51,16 +47,13 @@ | |
|
||
@Singleton | ||
public class RequestHelper { | ||
private static final Logger LOG = LoggerFactory.getLogger(RequestHelper.class); | ||
|
||
private final RequestManager requestManager; | ||
private final SingularityMailer mailer; | ||
private final DeployManager deployManager; | ||
private final SingularityValidator validator; | ||
private final UserManager userManager; | ||
private final TaskManager taskManager; | ||
private final SingularityDeployHealthHelper deployHealthHelper; | ||
private final TaskHistoryHelper taskHistoryHelper; | ||
|
||
@Inject | ||
public RequestHelper(RequestManager requestManager, | ||
|
@@ -69,16 +62,14 @@ public RequestHelper(RequestManager requestManager, | |
SingularityValidator validator, | ||
UserManager userManager, | ||
TaskManager taskManager, | ||
SingularityDeployHealthHelper deployHealthHelper, | ||
TaskHistoryHelper taskHistoryHelper) { | ||
SingularityDeployHealthHelper deployHealthHelper) { | ||
this.requestManager = requestManager; | ||
this.mailer = mailer; | ||
this.deployManager = deployManager; | ||
this.validator = validator; | ||
this.userManager = userManager; | ||
this.taskManager = taskManager; | ||
this.deployHealthHelper = deployHealthHelper; | ||
this.taskHistoryHelper = taskHistoryHelper; | ||
} | ||
|
||
public long unpause(SingularityRequest request, Optional<String> user, Optional<String> message, Optional<Boolean> skipHealthchecks) { | ||
|
@@ -237,7 +228,6 @@ public List<SingularityRequestParent> fillDataForRequestsAndFilter(List<Singular | |
Long lastActionTime = null; | ||
if (includeFullRequestData) { | ||
lastActionTime = getLastActionTimeForRequest( | ||
request.getRequest(), | ||
requestIdToLastHistory.getOrDefault(request.getRequest().getId(), Optional.empty()), | ||
Optional.ofNullable(deployStates.get(request.getRequest().getId())) | ||
); | ||
|
@@ -309,6 +299,7 @@ private Optional<SingularityTaskIdsByStatus> getTaskIdsByStatusForRequest(Singul | |
activeTaskIds.removeAll(cleaningTaskIds); | ||
|
||
List<SingularityTaskId> healthyTaskIds = new ArrayList<>(); | ||
List<SingularityTaskId> killedTaskIds = new ArrayList<>(); | ||
List<SingularityTaskId> notYetHealthyTaskIds = new ArrayList<>(); | ||
Map<String, List<SingularityTaskId>> taskIdsByDeployId = activeTaskIds.stream().collect(Collectors.groupingBy(SingularityTaskId::getDeployId)); | ||
for (Map.Entry<String, List<SingularityTaskId>> entry : taskIdsByDeployId.entrySet()) { | ||
|
@@ -319,15 +310,27 @@ private Optional<SingularityTaskIdsByStatus> getTaskIdsByStatusForRequest(Singul | |
entry.getValue(), | ||
pendingDeploy.isPresent() && pendingDeploy.get().getDeployMarker().getDeployId().equals(entry.getKey())); | ||
for (SingularityTaskId taskId : entry.getValue()) { | ||
if (healthyTasksIdsForDeploy.contains(taskId)) { | ||
if (taskManager.isKilledTask(taskId)) { | ||
killedTaskIds.add(taskId); | ||
} else if (healthyTasksIdsForDeploy.contains(taskId)) { | ||
healthyTaskIds.add(taskId); | ||
} else { | ||
notYetHealthyTaskIds.add(taskId); | ||
} | ||
} | ||
} | ||
|
||
return Optional.of(new SingularityTaskIdsByStatus(healthyTaskIds, notYetHealthyTaskIds, pendingTaskIds, cleaningTaskIds)); | ||
List<SingularityTaskId> loadBalanced = new ArrayList<>(); | ||
if (requestWithState.getRequest().isLoadBalanced()) { | ||
healthyTaskIds.stream() | ||
.filter(taskManager::isInLoadBalancer) | ||
.forEach(loadBalanced::add); | ||
cleaningTaskIds.stream() | ||
.filter(taskManager::isInLoadBalancer) | ||
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. does the task manager automatically update itself when tasks go in and out of the load balancer? 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. yeah, the isInLoadBalancer here is a live call to fetch the state (cached on the leader in memory) |
||
.forEach(loadBalanced::add); | ||
} | ||
|
||
return Optional.of(new SingularityTaskIdsByStatus(healthyTaskIds, notYetHealthyTaskIds, pendingTaskIds, cleaningTaskIds, loadBalanced, killedTaskIds)); | ||
} | ||
|
||
private boolean userAssociatedWithDeploy(Optional<SingularityRequestDeployState> deployState, SingularityUser user) { | ||
|
@@ -345,7 +348,7 @@ private boolean userModifiedRequestLast(Optional<SingularityRequestHistory> last | |
return lastHistory.isPresent() && userMatches(lastHistory.get().getUser(), user); | ||
} | ||
|
||
private long getLastActionTimeForRequest(SingularityRequest request, Optional<SingularityRequestHistory> lastHistory, Optional<SingularityRequestDeployState> deployState) { | ||
private long getLastActionTimeForRequest(Optional<SingularityRequestHistory> lastHistory, Optional<SingularityRequestDeployState> deployState) { | ||
long lastUpdate = 0; | ||
if (lastHistory.isPresent()) { | ||
lastUpdate = lastHistory.get().getCreatedAt(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,7 +25,7 @@ import { FetchTaskHistoryForRequest } from '../../actions/api/history'; | |
|
||
import TaskStateBreakdown from './TaskStateBreakdown'; | ||
|
||
const ActiveTasksTable = ({request, requestId, tasksAPI, healthyTaskIds, cleaningTaskIds, fetchTaskHistoryForRequest}) => { | ||
const ActiveTasksTable = ({request, requestId, tasksAPI, healthyTaskIds, cleaningTaskIds,loadBalancedTaskIds, killedTaskIds, fetchTaskHistoryForRequest}) => { | ||
const tasks = tasksAPI ? tasksAPI.data : []; | ||
const emptyTableMessage = (Utils.api.isFirstLoad(tasksAPI) | ||
? <p>Loading...</p> | ||
|
@@ -45,12 +45,34 @@ const ActiveTasksTable = ({request, requestId, tasksAPI, healthyTaskIds, cleanin | |
|
||
const tasksWithHealth = _.map(tasks, (task) => { | ||
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. could move this to mapStateToProps for cleanliness, but given that tasks might still be loading there I think it's fine to leave this as is |
||
let health; | ||
if (_.contains(healthyTaskIds, task.taskId.id)) { | ||
health = 'healthy'; | ||
} else if (_.contains(cleaningTaskIds, task.taskId.id)) { | ||
health = 'cleaning'; | ||
if (request.request.loadBalanced) { | ||
if (_.contains(healthyTaskIds, task.taskId.id)) { | ||
if (_.contains(loadBalancedTaskIds, task.taskId.id)) { | ||
health = 'healthy, in load balancer'; | ||
} else { | ||
health = 'healthy, awaiting load balancer'; | ||
} | ||
} else if (_.contains(cleaningTaskIds, task.taskId.id)) { | ||
if (_.contains(loadBalancedTaskIds, task.taskId.id)) { | ||
health = 'cleaning, in load balancer'; | ||
} else { | ||
health = 'cleaning, removed from load balancer'; | ||
} | ||
} else if (_.contains(killedTaskIds, task.taskId.id)) { | ||
health = 'terminating' | ||
} else { | ||
health = 'not yet healthy' | ||
} | ||
} else { | ||
health = 'not yet healthy' | ||
if (_.contains(healthyTaskIds, task.taskId.id)) { | ||
health = 'healthy'; | ||
} else if (_.contains(cleaningTaskIds, task.taskId.id)) { | ||
health = 'cleaning'; | ||
} else if (_.contains(killedTaskIds, task.taskId.id)) { | ||
health = 'terminating' | ||
} else { | ||
health = 'not yet healthy' | ||
} | ||
} | ||
return { | ||
...task, | ||
|
@@ -86,6 +108,8 @@ ActiveTasksTable.propTypes = { | |
tasksAPI: PropTypes.object.isRequired, | ||
healthyTaskIds: PropTypes.array.isRequired, | ||
cleaningTaskIds: PropTypes.array.isRequired, | ||
loadBalancedTaskIds: PropTypes.array.isRequired, | ||
killedTaskIds: PropTypes.array.isRequired, | ||
fetchTaskHistoryForRequest: PropTypes.func.isRequired | ||
}; | ||
|
||
|
@@ -100,7 +124,13 @@ const mapStateToProps = (state, ownProps) => { | |
healthyTaskIds: _.map(Utils.maybe(request, ['taskIds', 'healthy'], []), (task) => { | ||
return task.id; | ||
}), | ||
cleaningTaskIds: _.map(Utils.maybe(request, ['data', 'taskIds', 'cleaning'], []), (task) => { | ||
cleaningTaskIds: _.map(Utils.maybe(request, ['taskIds', 'cleaning'], []), (task) => { | ||
return task.id; | ||
}), | ||
loadBalancedTaskIds: _.map(Utils.maybe(request, ['taskIds', 'loadBalanced'], []), (task) => { | ||
return task.id; | ||
}), | ||
killedTaskIds: _.map(Utils.maybe(request, ['taskIds', 'killed'], []), (task) => { | ||
return task.id; | ||
}) | ||
}}; | ||
|
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.
iirc you get an exception if you try to add to an emptyList(), might want to construct new lists to avoid a gotcha if this wasn't intentional
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.
Was debating that, figured I'd tend towards treating as immutable. In most places in the code we try and do that, and make copies fo lists where appropriate if we are going to build on them