/**
   * Private method that determines whether a given task should be re-tried based on the given
   * {@code Throwable} that caused failure. If this returns {@code true} then the task should be
   * re-tried. Otherwise, the task should be dropped.
   */
  private boolean shouldRetry(ScheduledTaskImpl task, Throwable t) {
    // NOTE: as a first-pass implementation this simply instructs the
    // caller to try again if retry is requested, but other strategies
    // (like the number of times re-tried) might be considered later
    if ((t instanceof ExceptionRetryStatus) && (((ExceptionRetryStatus) t).shouldRetry())) {
      return true;
    }

    // we're not re-trying the task, so log that it's being dropped
    if (logger.isLoggable(Level.WARNING)) {
      if (task.isRecurring()) {
        logger.logThrow(
            Level.WARNING,
            t,
            "skipping a recurrence of "
                + "a task that failed with a non-retryable "
                + "exception: {0}",
            task);
      } else {
        logger.logThrow(
            Level.WARNING,
            t,
            "dropping a task that " + "failed with a non-retryable exception: {0}",
            task);
      }
    }

    return false;
  }
    /** {@inheritDoc} */
    public void run() {
      logger.log(Level.FINE, "Starting a consumer for transactions");
      notifyThreadJoining();

      try {
        while (true) {
          // wait for the next task, at which point we may get
          // interrupted and should therefore return
          ScheduledTaskImpl task = (ScheduledTaskImpl) (backingQueue.getNextTask(true));

          // run the task, checking if it completed
          if (executeTask(task, false, true)) {
            // if it's a recurring task, schedule the next run
            if (task.isRecurring()) {
              long nextStart = task.getStartTime() + task.getPeriod();
              task = new ScheduledTaskImpl(task, nextStart);
              backingQueue.addTask(task);
            }
            // if it has dependent tasks, schedule the next one
            TaskQueueImpl queue = (TaskQueueImpl) (task.getTaskQueue());
            if (queue != null) {
              queue.scheduleNextTask();
            }
          }
        }
      } catch (InterruptedException ie) {
        if (logger.isLoggable(Level.FINE)) {
          logger.logThrow(Level.FINE, ie, "Consumer is finishing");
        }
      } catch (Exception e) {
        // this should never happen, since running the task should
        // never throw an exception that isn't handled
        logger.logThrow(Level.SEVERE, e, "Fatal error for consumer");
      } finally {
        notifyThreadLeaving();
      }
    }