@Override
  public void dispose() {
    if (logger.isDebugEnabled()) {
      logger.debug("Waiting for works to finish execution");
    }

    long initialMillis = System.currentTimeMillis();

    while (workTracker.pendingWorks().size() != 0 && !isTimeoutExpired(initialMillis)) {
      try {
        Thread.sleep(waitMillis);
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
      }
    }

    if (logger.isDebugEnabled()) {
      logger.debug(
          String.format(
              "Stop waiting for works completion. There are %s works unfinished works",
              workTracker.pendingWorks().size()));
    }

    workTracker.dispose();
  }
  @Override
  public long startWork(
      final Work work,
      long startTimeout,
      ExecutionContext execContext,
      final WorkListener workListener)
      throws WorkException {
    try {
      workTracker.addWork(work);

      TrackeableWork trackeableWork = new TrackeableWork(work);
      return delegateHolder
          .getWorkManager()
          .startWork(
              trackeableWork,
              startTimeout,
              execContext,
              workListenerWrapperFactory.create(work, workListener));
    } catch (WorkException e) {
      workTracker.removeWork(work);
      throw e;
    } catch (RuntimeException e) {
      workTracker.removeWork(work);
      throw e;
    }
  }
  @Override
  public void doWork(Work work) throws WorkException {
    workTracker.addWork(work);

    try {
      delegateHolder.getWorkManager().doWork(work);
    } finally {
      workTracker.removeWork(work);
    }
  }
  @Override
  public void execute(final Runnable runnable) {
    try {
      workTracker.addWork(runnable);

      delegateHolder.getWorkManager().execute(new TrackeableRunnable(runnable));
    } catch (RuntimeException e) {
      workTracker.removeWork(runnable);
      throw e;
    }
  }
  @Override
  public void doWork(
      Work work, long startTimeout, ExecutionContext execContext, WorkListener workListener)
      throws WorkException {
    workTracker.addWork(work);

    try {
      delegateHolder.getWorkManager().doWork(work, startTimeout, execContext, workListener);
    } finally {
      workTracker.removeWork(work);
    }
  }
  @Override
  public void scheduleWork(final Work work) throws WorkException {
    try {
      workTracker.addWork(work);

      Work wrappedWork = new TrackeableWork(work);

      delegateHolder.getWorkManager().scheduleWork(wrappedWork);
    } catch (WorkException e) {
      workTracker.removeWork(work);
      throw e;
    } catch (RuntimeException e) {
      workTracker.removeWork(work);
      throw e;
    }
  }