protected void schedule(Task task, Pair<String, Trigger> triggerAndExpression) { if (triggerAndExpression == null) { throw new IllegalArgumentException("Must specify a Trigger and its expression"); } LOGGER.info( "Scheduling task [{}] with trigger expression [{}]", task.id, triggerAndExpression.getFirst()); task.execution = taskScheduler.schedule(task.runnable, triggerAndExpression.getSecond()); task.executingTriggerExpression = triggerAndExpression.getFirst(); task.executingTrigger = triggerAndExpression.getSecond(); }
/** * Reads latest config from {@link ConfigService} for the given {@link Task} and caches it in that * {@link Task}. If config is found but can't be parsed, the {@link Task}'s {@code configured*} * fields will include the bad {@link Trigger} expression and a {@link BadConfigTrigger}. If * config simply can't be read at all, e.g. network outage, that will just be logged and the * {@link Task}'s config will be unchanged. * * <p>This also handles initialization of the {@link Task's} default {@link Trigger} <em>every * time</em>. Which means you can technically change the default and it will be picked up. * * @param task * @return * @throws BadTriggerConfigException if the default configuration for the given {@link Task} is * broken. Exceptions during read of latest config from {@link ConfigService} are caught and * handled. */ protected void mergeLatestTriggerConfig(Task task) throws BadTriggerConfigException { // Null will mean "have no idea what the latest config would be or // if it even exists." Everything else will mean "either found good // config, use it, or found bad config and it's up to you what to do // with it." Pair<String, Trigger> newTriggerConfig = null; try { newTriggerConfig = readNewTriggerConfig(task.triggerExpressionConfigName); } catch (BadTriggerConfigException e) { LOGGER.warn( "Unable to parse task [{}] trigger config named [{}].", new Object[] {task.id, task.triggerExpressionConfigName, e}); newTriggerConfig = new Pair<String, Trigger>(null, new BadConfigTrigger(e.getConfig(), e)); } catch (RuntimeException e) { // Probably db connection or other systemic issue issue. Will end up // leaving this task alone. LOGGER.error( "Unable to read trigger config named [{}]. This" + " was probably a transient and/or systemic issue " + " rather than a parse issue.", task.triggerExpressionConfigName, e); } if (newTriggerConfig != null && newTriggerConfig.getSecond() == null) { // Really a programmer error but let's just quietly normalize to // simplify boolean expressions below. newTriggerConfig = null; } if (newTriggerConfig == null) { task.configuredTriggerExpression = null; task.configuredTrigger = null; } else { task.configuredTriggerExpression = newTriggerConfig.getFirst(); task.configuredTrigger = newTriggerConfig.getSecond(); } // Do this every time to avoid weird stuff from mis-use where the // expression and trigger don't match. task.defaultTrigger = parseTriggerConfig(task.defaultTriggerExpression); }
protected void maybeReschedule(Task task) { Pair<String, Trigger> configuredOrDefault = configuredOrDefaultTrigger(task); Pair<String, Trigger> newTrigger = null; if (task.executingTrigger == null) { // first time execution newTrigger = configuredOrDefault; LOGGER.debug( "Preparing to schedule task [{}] for" + " first-time execution with trigger expression [{}]", task.id, newTrigger.getFirst()); } else if (configuredOrDefault.getSecond() instanceof BadConfigTrigger) { // broken config. nothing to do. LOGGER.info( "Skipping scheduling for task [{}] because it has" + " a bad trigger expression [{}]", task.id, configuredOrDefault.getFirst()); } else if (!(configuredOrDefault.getFirst().equals(task.executingTriggerExpression))) { // schedule change! newTrigger = configuredOrDefault; LOGGER.debug( "Preparing to re-schedule task [{}] with trigger" + " expression [{}]. Previous expression: [{}]", new Object[] {task.id, newTrigger.getFirst(), task.executingTriggerExpression}); } else { LOGGER.debug( "Skipping scheduling for task [{}] because no" + " changes have been requested. Currently executing" + " trigger expression: [{}]", task.id, task.executingTriggerExpression); return; } cancel(task); schedule(task, newTrigger); }