in genie-web/src/main/java/com/netflix/genie/web/services/impl/JobDirectoryServerServiceImpl.java [147:246]
public void serveResource(
final String id,
final URL baseUrl,
final String relativePath,
final HttpServletRequest request,
final HttpServletResponse response
) throws GenieException {
final long start = System.nanoTime();
final Set<Tag> tags = Sets.newHashSet();
try {
// Normalize the base url. Make sure it ends in /.
final URI baseUri = new URI(baseUrl.toString() + SLASH).normalize();
// Lookup archive status and job execution type
final ArchiveStatus archiveStatus = this.persistenceService.getJobArchiveStatus(id);
tags.add(Tag.of(ARCHIVE_STATUS_TAG, archiveStatus.name()));
final DirectoryManifest manifest;
final URI jobDirRoot;
switch (archiveStatus) {
case NO_FILES:
// Job failed before any files were created. Nothing to serve.
throw new GenieNotFoundException("Job failed before any file was created: " + id);
case FAILED:
// Archive failed (also implies job is done). Return 404 without further processing
throw new GenieNotFoundException("Job failed to archive files: " + id);
case DISABLED:
// Not a possible state in database as of now [GENIE-657]
throw new GeniePreconditionException("Archive disabled for job " + id);
case UNKNOWN:
// Set by the server when an agent is AWOL long enough.
// Archive status is truly unknown. As of now, fall-through and attempt serving from archive.
case ARCHIVED:
// Serve file from archive
log.debug("Routing request to archive");
final ArchivedJobMetadata archivedJobMetadata = this.archivedJobService.getArchivedJobMetadata(id);
final String rangeHeader = request.getHeader(HttpHeaders.RANGE);
manifest = archivedJobMetadata.getManifest();
final URI baseJobDirRoot = archivedJobMetadata.getArchiveBaseUri();
jobDirRoot = new URIBuilder(baseJobDirRoot).setFragment(rangeHeader).build();
break;
case PENDING:
log.debug("Routing request to connected agent");
if (!this.agentRoutingService.isAgentConnectionLocal(id)) {
throw new GenieServerUnavailableException("Agent connection has moved or was terminated");
}
manifest = this.agentFileStreamService.getManifest(id).orElseThrow(
() -> new GenieServerUnavailableException("Manifest not found for job " + id)
);
jobDirRoot = AgentFileProtocolResolver.createUri(
id,
SLASH,
request.getHeader(HttpHeaders.RANGE)
);
break;
default:
throw new GenieServerException("Unknown archive status " + archiveStatus + "(" + id + ")");
}
log.debug(
"Serving file: {} for job: {} (archive status: {})",
relativePath,
id,
archiveStatus
);
// Common handling of archived, locally running v3 job or locally connected v4 job
this.handleRequest(baseUri, relativePath, request, response, manifest, jobDirRoot);
MetricsUtils.addSuccessTags(tags);
} catch (NotFoundException e) {
MetricsUtils.addFailureTagsWithException(tags, e);
throw new GenieNotFoundException(e.getMessage(), e);
} catch (IOException e) {
MetricsUtils.addFailureTagsWithException(tags, e);
throw new GenieServerException("Error serving response: " + e.getMessage(), e);
} catch (URISyntaxException e) {
MetricsUtils.addFailureTagsWithException(tags, e);
throw new GenieServerException(e.getMessage(), e);
} catch (final JobNotArchivedException e) {
MetricsUtils.addFailureTagsWithException(tags, e);
throw new GeniePreconditionException("Job outputs were not archived", e);
} catch (final JobNotFoundException | JobDirectoryManifestNotFoundException e) {
MetricsUtils.addFailureTagsWithException(tags, e);
throw new GenieNotFoundException("Failed to retrieve job archived files metadata", e);
} catch (GenieException e) {
MetricsUtils.addFailureTagsWithException(tags, e);
throw e;
} finally {
final long elapsed = System.nanoTime() - start;
this.meterRegistry.timer(SERVE_RESOURCE_TIMER, tags).record(elapsed, TimeUnit.NANOSECONDS);
}
}