@Override protected final Document encode(final JobInfo job) { final Document document = new Document() .append(JobStructure.ID.key(), job.getJobId()) .append(JobStructure.JOB_TYPE.key(), job.getJobType()) .append(JobStructure.STARTED.key(), Date.from(job.getStarted().toInstant())) .append(JobStructure.LAST_UPDATED.key(), Date.from(job.getLastUpdated().toInstant())) .append(JobStructure.MESSAGES.key(), job.getMessages().stream() .map(MongoJobRepository::encodeJobMessage) .collect(toList())) .append(JobStructure.STATUS.key(), job.getStatus().name()) .append(JobStructure.HOSTNAME.key(), job.getHostname()); if (job.isStopped()) { document.append(JobStructure.STOPPED.key(), Date.from(job.getStopped().get().toInstant())); } return document; }
private JobInfo createJobInfo(final String jobType) { return newJobInfo(uuidProvider.getUuid(), jobType, clock, systemInfo.getHostname()); }
private JobInfo.Builder defaultJobInfo() { return newJobInfo(JOB_ID, JOB_TYPE, clock, HOSTNAME).copy(); }
public String getStopped() { return job.isStopped() ? formatTime(job.getStopped().get()) : ""; }
/** * Returns additional information like job uri, running state, started and stopped timestamps. * * @param jobInfo the job information of the last job * @return map containing uri, starting, and running or stopped entries. */ protected Map<String, String> runningDetailsFor(final JobInfo jobInfo) { final Map<String, String> details = new HashMap<>(); details.put("Started", ISO_DATE_TIME.format(jobInfo.getStarted())); if (jobInfo.getStopped().isPresent()) { details.put("Stopped", ISO_DATE_TIME.format(jobInfo.getStopped().get())); } return details; }
public String getRuntime() { return job.isStopped() ? formatRuntime(job.getStarted(), job.getStopped().get()) : formatRuntime(job.getStarted(), OffsetDateTime.now()); }
private JobInfo someRunningJob(final JobInfo.JobStatus jobStatus, int startedSecondsAgo) { OffsetDateTime now = now(); JobInfo someJob = mock(JobInfo.class); when(someJob.getJobType()).thenReturn("someJobType"); when(someJob.getJobId()).thenReturn("someJobId"); when(someJob.getStarted()).thenReturn(now.minusSeconds(startedSecondsAgo)); when(someJob.getStopped()).thenReturn(empty()); when(someJob.getStatus()).thenReturn(jobStatus); return someJob; } }
@Test public void shouldFindAll() { // given repository.createOrUpdate(newJobInfo("oldest", "FOO", fixed(Instant.now().minusSeconds(1), systemDefault()), "localhost")); repository.createOrUpdate(newJobInfo("youngest", "FOO", fixed(Instant.now(), systemDefault()), "localhost")); // when final List<JobInfo> jobInfos = repository.findAll(); // then assertThat(jobInfos.size(), is(2)); assertThat(jobInfos.get(0).getJobId(), is("youngest")); assertThat(jobInfos.get(1).getJobId(), is("oldest")); }
@Test public void shouldKillJobsWithoutUpdateSince() { JobInfo toBeKilled = defaultJobInfo("toBeKilled", 75); jobRepository.createOrUpdate(toBeKilled); jobService.killJobsDeadSince(60); Optional<JobInfo> expectedKilledJob = jobRepository.findOne(toBeKilled.getJobId()); assertThat(expectedKilledJob.get().isStopped(), is(true)); assertThat(expectedKilledJob.get().getStatus(), is(DEAD)); }
@Override protected final String keyOf(final JobInfo value) { return value.getJobId(); }
final String message; final JobInfo currentJob = jobInfos.get(0); final JobInfo lastJob = (!currentJob.getStopped().isPresent() && currentJob.getStatus() == JobStatus.OK && jobInfos.size() > 1) ? jobInfos.get(1) : jobInfos.get(0); final JobMeta jobMeta = getJobMeta(jobDefinition.jobType()); long numFailedJobs = getNumFailedJobs(jobInfos); if (!jobMeta.isDisabled()) { switch(lastJob.getStatus()) { case OK: case SKIPPED: message, asList( link(REL_JOB, String.format("%s/jobs/%s", managementContextPath, lastJob.getJobId()), "Details") ), runningDetailsFor(lastJob)
@Test public void shouldRunJob() { // given: String jobType = "bar"; when(jobRunnable.getJobDefinition()).thenReturn(someJobDefinition(jobType)); // when: Optional<String> optionalJobId = jobService.startAsyncJob(jobType); // then: final JobInfo expectedJobInfo = JobInfo.newJobInfo(optionalJobId.get(), jobType, clock, systemInfo.hostname); verify(executorService).execute(any(Runnable.class)); verify(jobRepository).createOrUpdate(expectedJobInfo); verify(jobRunnable).execute(); verify(jobMetaService).aquireRunLock(expectedJobInfo.getJobId(), expectedJobInfo.getJobType()); }
@Test public void shouldAppendMessageToJobInfo() throws Exception { String someUri = "someUri"; OffsetDateTime now = now(); //Given JobInfo jobInfo = newJobInfo(someUri, "TEST", systemDefaultZone(), "localhost"); repository.createOrUpdate(jobInfo); //When JobMessage igelMessage = JobMessage.jobMessage(Level.WARNING, "Der Igel ist froh.", now); repository.appendMessage(someUri, igelMessage); //Then JobInfo jobInfoFromRepo = repository.findOne(someUri).get(); assertThat(jobInfoFromRepo.getMessages().size(), is(1)); assertThat(jobInfoFromRepo.getMessages().get(0), is(igelMessage)); assertThat(jobInfoFromRepo.getLastUpdated(), is(now.truncatedTo(ChronoUnit.MILLIS))); }
private List<JobInfo> findJobsToDelete(final List<JobInfo> jobs) { List<JobInfo> jobsToDelete = new ArrayList<>(); jobs.stream() .sorted(comparing(JobInfo::getStarted, reverseOrder())) .collect(groupingBy(JobInfo::getJobType)) .forEach((jobType, jobExecutions) -> { Optional<JobInfo> lastOkExecution = jobExecutions.stream() .filter(j -> j.isStopped() && j.getStatus() == OK) .findFirst(); jobExecutions.stream() .filter(JobInfo::isStopped) .skip(numberOfJobsToKeep) .filter(j -> !(lastOkExecution.isPresent() && lastOkExecution.get().equals(j))) .forEach(jobsToDelete::add); }); return jobsToDelete; }
public List<Link> getLinks() { final String jobUri = String.format("%s%s/jobs/%s", baseUri, edisonManagementBasePath, job.getJobId()); return asList( link("self", jobUri, "Self"), link("http://github.com/otto-de/edison/link-relations/job/definition", String.format("%s%s/jobdefinitions/%s", baseUri, edisonManagementBasePath, job.getJobType()), "Job Definition"), link("collection", jobUri.substring(0, jobUri.lastIndexOf("/")), "All Jobs"), link("collection/" + getJobType(), jobUri.substring(0, jobUri.lastIndexOf("/")) + "?type=" + getJobType(), "All " + getJobType() + " Jobs") ); }
public String getJobType() { return job.getJobType(); }
@Override public List<JobInfo> findRunningWithoutUpdateSince(OffsetDateTime timeOffset) { return jobs.values().stream() .filter(jobInfo -> !jobInfo.isStopped() && jobInfo.getLastUpdated().isBefore(timeOffset)) .collect(toList()); }
private List<JobInfo> findJobsToDelete(final List<JobInfo> jobs) { List<JobInfo> jobsToDelete = new ArrayList<>(); jobs.stream() .sorted(comparing(JobInfo::getStarted, reverseOrder())) .collect(groupingBy(JobInfo::getJobType)) .forEach((jobType, jobExecutions) -> { jobExecutions.stream() .filter(j -> j.isStopped() && Objects.equals(j.getStatus(), SKIPPED)) .skip(numberOfJobsToKeep) .forEach(jobsToDelete::add); }); return jobsToDelete; } }
@Test public void shouldFindAllJobsOfSpecificType() throws Exception { // Given final String type = "TEST"; final String otherType = "OTHERTEST"; repository.createOrUpdate(builder() .setJobId("1") .setJobType(type) .setStarted(now(fixed(Instant.now().minusSeconds(10), systemDefault()))) .setStopped(now(fixed(Instant.now().minusSeconds(7), systemDefault()))) .setHostname("localhost") .setStatus(JobStatus.OK) .build()); repository.createOrUpdate(newJobInfo("2", otherType, systemDefaultZone(), "localhost")); repository.createOrUpdate(newJobInfo("3", type, systemDefaultZone(), "localhost")); // When final List<JobInfo> jobsType1 = repository.findByType(type); final List<JobInfo> jobsType2 = repository.findByType(otherType); // Then assertThat(jobsType1.size(), is(2)); assertThat(jobsType1.stream().anyMatch(job -> job.getJobId().equals("1")), is(true)); assertThat(jobsType1.stream().anyMatch(job -> job.getJobId().equals("3")), is(true)); assertThat(jobsType2.size(), is(1)); assertThat(jobsType2.stream().anyMatch(job -> job.getJobId().equals("2")), is(true)); }
@Test public void shouldKeepAtLeastOneSuccessfulJob() { // given JobInfo job = builder() .setJobId("foobar") .setJobType("TYPE") .setStarted(now(muchEarlier)) .setStopped(now(now)) .setHostname("localhost") .setStatus(ERROR) .build(); JobRepository repository = new InMemJobRepository() {{ createOrUpdate(job.copy().setStatus(OK).build()); createOrUpdate(job.copy().setStarted(now(now)).setJobId("foo").build()); createOrUpdate(job.copy().setJobId("bar").setStarted(now(earlier)).build()); createOrUpdate(job.copy().setJobId("barzig").setStarted(now(evenEarlier)).build()); createOrUpdate(job.copy().setJobId("foozification").setStarted(now(evenEarlier)).build()); }}; KeepLastJobs strategy = new KeepLastJobs(repository, 2); // when strategy.doCleanUp(); // then assertThat(repository.size(), is(3L)); assertThat(repository.findOne("foo"), isPresent()); assertThat(repository.findOne("bar"), isPresent()); assertThat(repository.findOne("barzig"), isAbsent()); assertThat(repository.findOne("foobar"), isPresent()); assertThat(repository.findOne("foozification"), isAbsent()); }