in genie-web/src/main/java/com/netflix/genie/web/services/impl/JobResolverServiceImpl.java [346:445]
private void resolveCommand(final JobResolutionContext context) throws GenieJobResolutionException {
final long start = System.nanoTime();
final Set<Tag> tags = new HashSet<>();
try {
final JobRequest jobRequest = context.getJobRequest();
final Criterion criterion = jobRequest.getCriteria().getCommandCriterion();
//region Algorithm Step 1
final Set<Command> commands = this.persistenceService.findCommandsMatchingCriterion(criterion, true);
// Short circuit if there are no commands
if (commands.isEmpty()) {
throw new GenieJobResolutionException("No command matching command criterion found");
}
//endregion
//region Algorithm Step 2
final Map<Command, List<Criterion>> commandClusterCriterions = this.generateClusterCriteriaPermutations(
commands,
jobRequest
);
final Set<Criterion> uniqueCriteria = this.flattenClusterCriteriaPermutations(commandClusterCriterions);
final Set<Cluster> allCandidateClusters = this.persistenceService.findClustersMatchingAnyCriterion(
uniqueCriteria,
true
);
if (allCandidateClusters.isEmpty()) {
throw new GenieJobResolutionException("No clusters available to run any candidate command on");
}
//endregion
//region Algorithm Step 3
final Map<Command, Set<Cluster>> commandClusters = this.generateCommandClustersMap(
commandClusterCriterions,
allCandidateClusters
);
// this should never really happen based on above check but just in case
if (commandClusters.isEmpty()) {
throw new GenieJobResolutionException("No clusters available to run any candidate command on");
}
// save the map for use later by cluster resolution
context.setCommandClusters(commandClusters);
//endregion
//region Algorithm Step 4
final ResourceSelectionResult<Command> result = this.commandSelector.select(
new CommandSelectionContext(
context.getJobId(),
jobRequest,
context.isApiJob(),
commandClusters
)
);
//endregion
final Command command = result
.getSelectedResource()
.orElseThrow(
() -> new GenieJobResolutionException(
"Expected a command but "
+ result.getSelectorClass().getSimpleName()
+ " didn't select anything. Rationale: "
+ result.getSelectionRationale().orElse(NO_RATIONALE)
)
);
LOG.debug(
"Selected command {} for criterion {} using {} due to {}",
command.getId(),
criterion,
result.getSelectorClass().getName(),
result.getSelectionRationale().orElse(NO_RATIONALE)
);
MetricsUtils.addSuccessTags(tags);
final String commandId = command.getId();
final String commandName = command.getMetadata().getName();
tags.add(Tag.of(MetricsConstants.TagKeys.COMMAND_ID, commandId));
tags.add(Tag.of(MetricsConstants.TagKeys.COMMAND_NAME, commandName));
final SpanCustomizer spanCustomizer = context.getSpanCustomizer();
this.tagAdapter.tag(spanCustomizer, TracingConstants.JOB_COMMAND_ID_TAG, commandId);
this.tagAdapter.tag(spanCustomizer, TracingConstants.JOB_COMMAND_NAME_TAG, commandName);
context.setCommand(command);
} catch (final GenieJobResolutionException e) {
// No candidates or selector choose none
tags.add(NO_COMMAND_RESOLVED_ID);
tags.add(NO_COMMAND_RESOLVED_NAME);
MetricsUtils.addFailureTagsWithException(tags, e);
throw e;
} catch (final ResourceSelectionException t) {
// Selector runtime error
MetricsUtils.addFailureTagsWithException(tags, t);
throw new GenieJobResolutionRuntimeException(t);
} finally {
this.registry
.timer(RESOLVE_COMMAND_TIMER, tags)
.record(System.nanoTime() - start, TimeUnit.NANOSECONDS);
}
}