private void jobFate (FinishTimeInfo finishTimeInfo, String appType, long applicableFinishTime,
        long jobFinishTime) {
      if (_analyticJob != null && _analyticJob.retry()) {
        logger.warn("Add analytic job id [" + _analyticJob.getAppId() + "] into the retry list.");
        _analyticJobGenerator.addIntoRetries(_analyticJob);
      } else if (_analyticJob != null && _analyticJob.isSecondPhaseRetry()) {
        //Putting the job into a second retry queue which fetches jobs after some interval. Some spark jobs may need
        // more time than usual to process, hence the queue.
        logger.warn("Add analytic job id [" + _analyticJob.getAppId() + "] into the second retry list.");
        _analyticJobGenerator.addIntoSecondRetryQueue(_analyticJob);
      } else {
        if (_analyticJob != null) {
          MetricsController.markSkippedJob();
          logger.error("Drop the analytic job. Reason: reached the max retries for application id = ["
                  + _analyticJob.getAppId() + "].");
          // Job is being dropped. Clean it up from corresponding maps.
          _appToAnalyticJobMap.remove(_analyticJob.getAppId());
          if (finishTimeInfo != null) {
            synchronized (_appsLock) {
              boolean saveSucceeded = false;
              long finishTime = (applicableFinishTime == -1) ?
                  getApplicableFinishTime(_analyticJob) : applicableFinishTime;
              // As this job has failed, its possible that this may have been the one with lowest finish time, hence
              // backfill_info table may have to be updated.
              BackfillInfo backfillInfo = null;
              try {
                backfillInfo = getBackfillInfoForSave(finishTimeInfo, appType, finishTime);
                // We do not retry currently, if DB operation fails while saving backfill_info.
                if (backfillInfo != null) {
                  backfillInfo.save();
                }
                saveSucceeded = true;
              } catch(Exception e) {
                logger.warn("Exception thrown while saving to backfill_info" + e.getMessage());
                logger.warn(ExceptionUtils.getStackTrace(e));
              }
              if (saveSucceeded) {
                // As the job analysis failed, no need to update max finish time.
                updateLastBackfillTsSaved(finishTimeInfo, backfillInfo);
              }
              // Remove from finish times map irrespective of failure during save. Rely on backfill ts to be updated
              // correctly on next run of analysis job.
              removeFromFinishTimesMap(finishTimeInfo._appFinishTimesMap, finishTime);
            }
          }
        }
      }
    }
Get applicable finish time used while storing in app finish times map. This would typically be the app finish
time for apps fetched from RM. But for backfill jobs, if finish time could not be determined at the time of
fetching jobs for backfill, we will use the backfill ts fetched from backfill_info table instead (0 will be used
if an entry in backfill_info table could not be found as well).

@return applicable finish time.
app/com/linkedin/drelephant/ElephantRunner.java