private Runnable getDeferredEvaluator(final IInstanceKey instance, final IJobUpdateKey key) { return () -> storage.write( (NoResult.Quiet) storeProvider -> { IJobUpdateSummary summary = getOnlyMatch(storeProvider.getJobUpdateStore(), queryByUpdate(key)); JobUpdateStatus status = summary.getState().getStatus(); // Suppress this evaluation if the updater is not currently active. if (JobUpdateStateMachine.isActive(status)) { UpdateFactory.Update update = updates.get(instance.getJobKey()); try { evaluateUpdater( storeProvider, update, summary, ImmutableMap.of( instance.getInstanceId(), getActiveInstance( storeProvider.getTaskStore(), instance.getJobKey(), instance.getInstanceId()))); } catch (UpdateStateException e) { throw Throwables.propagate(e); } } }); }
@Override public JobUpdatePulseStatus pulse(final IJobUpdateKey key) throws UpdateStateException { final PulseState state = pulseHandler.pulseAndGet(key); if (state == null) { LOG.info("Not pulsing inactive job update: " + key); return JobUpdatePulseStatus.FINISHED; } LOG.fine( String.format( "Job update %s has been pulsed. Timeout of %d msec is reset.", key, state.getPulseTimeoutMs())); if (JobUpdateStateMachine.isAwaitingPulse(state.getStatus())) { // Attempt to unblock a job update previously blocked on expired pulse. executor.execute( () -> { try { unscopedChangeUpdateStatus( key, status -> new JobUpdateEvent().setStatus(GET_UNBLOCKED_STATE.apply(status))); } catch (UpdateStateException e) { LOG.severe("Error while processing job update pulse: " + e); } }); } return JobUpdatePulseStatus.OK; }
private void changeJobUpdateStatus( MutableStoreProvider storeProvider, IJobUpdateKey key, JobUpdateEvent proposedEvent, boolean recordChange) throws UpdateStateException { JobUpdateStatus status; boolean record; JobUpdateStore.Mutable updateStore = storeProvider.getJobUpdateStore(); Optional<String> updateLock = updateStore.getLockToken(key); if (updateLock.isPresent()) { status = proposedEvent.getStatus(); record = recordChange; } else { LOG.severe("Update " + key + " does not have a lock"); status = ERROR; record = true; } LOG.info(String.format("Update %s is now in state %s", key, status)); if (record) { updateStore.saveJobUpdateEvent( key, IJobUpdateEvent.build(proposedEvent.setTimestampMs(clock.nowMillis()).setStatus(status))); } if (TERMINAL_STATES.contains(status)) { if (updateLock.isPresent()) { lockManager.releaseLock( ILock.build( new Lock() .setKey(LockKey.job(key.getJob().newBuilder())) .setToken(updateLock.get()))); } pulseHandler.remove(key); } else { pulseHandler.updatePulseStatus(key, status); } MonitorAction action = JobUpdateStateMachine.getActionForStatus(status); IJobKey job = key.getJob(); if (action == STOP_WATCHING) { updates.remove(job); } else if (action == ROLL_FORWARD || action == ROLL_BACK) { if (action == ROLL_BACK) { updates.remove(job); } else { checkState(!updates.containsKey(job), "Updater already exists for " + job); } IJobUpdate jobUpdate = updateStore.fetchJobUpdate(key).get(); UpdateFactory.Update update; try { update = updateFactory.newUpdate(jobUpdate.getInstructions(), action == ROLL_FORWARD); } catch (RuntimeException e) { LOG.log(Level.WARNING, "Uncaught exception: " + e, e); changeJobUpdateStatus( storeProvider, key, newEvent(ERROR).setMessage("Internal scheduler error: " + e.getMessage()), true); return; } updates.put(job, update); evaluateUpdater(storeProvider, update, jobUpdate.getSummary(), ImmutableMap.of()); } }