docs: private void processReturnedTask(Future<OptimizationResult> future) {
          long currentTime = System.currentTimeMillis();
          OptimizationResult result;
          try {
              result = future.get(100, TimeUnit.MILLISECONDS);
          } catch (InterruptedException e) {
              throw new RuntimeException("Unexpected InterruptedException thrown for task", e);
          } catch (ExecutionException e) {
              //Note that most of the time, an OptimizationResult is returned even for an exception
              //This is just to handle any that are missed there (or, by implementations that don't properly do this)
              log.warn("Task failed", e);
  
              numCandidatesFailed.getAndIncrement();
              return;
          } catch (TimeoutException e) {
              throw new RuntimeException(e); //TODO
          }
  
          //Update internal status:
          CandidateInfo status = currentStatus.get(result.getIndex());
          CandidateInfo newStatus = new CandidateInfo(result.getIndex(), result.getCandidateInfo().getCandidateStatus(),
                  result.getScore(), status.getCreatedTime(), result.getCandidateInfo().getStartTime(),
                  currentTime, status.getFlatParams(), result.getCandidateInfo().getExceptionStackTrace());
          currentStatus.put(result.getIndex(), newStatus);
  
          //Listeners (on complete, etc) should be executed in underlying task
  
  
          if (result.getCandidateInfo().getCandidateStatus() == CandidateStatus.Failed) {
              log.info("Task {} failed during execution: {}", result.getIndex(), result.getCandidateInfo().getExceptionStackTrace());
              numCandidatesFailed.getAndIncrement();
          } else {
  
              //Report completion to candidate generator
              config.getCandidateGenerator().reportResults(result);
  
              Double score = result.getScore();
              log.info("Completed task {}, score = {}", result.getIndex(), result.getScore());
  
              boolean minimize = config.getScoreFunction().minimize();
              if (score != null && (bestScore == null
                      || ((minimize && score < bestScore) || (!minimize && score > bestScore)))) {
                  if (bestScore == null) {
                      log.info("New best score: {} (first completed model)", score);
                  } else {
                      int idx = result.getIndex();
                      int lastBestIdx = bestScoreCandidateIndex.get();
                      log.info("New best score: {}, model {} (prev={}, model {})", score, idx, bestScore, lastBestIdx);
                  }
                  bestScore = score;
                  bestScoreTime = System.currentTimeMillis();
                  bestScoreCandidateIndex.set(result.getIndex());
              }
              numCandidatesCompleted.getAndIncrement();
  
              //Model saving is done in the optimization tasks, to avoid CUDA threading issues
              ResultReference resultReference = result.getResultReference();
  
              if (resultReference != null)
                  allResults.add(resultReference);
          }
      }