code: public void doRecovery(){
          try {
              boolean toRestart = Boolean.getBoolean("cloudslang.worker.restart.on.recovery");
              //If we are configured to restart on recovery - do shutdown
              if(toRestart){
                  logger.warn("Worker is configured to restart on recovery and since internal recovery is needed the process is exiting...");
                  System.exit(EXIT_STATUS);
              }
  
              synchronized (this){
                  //If already in recovery - then return and do nothing
                  if(inRecovery){
                      return;
                  }
                  inRecovery = true;
  
              }
              syncManager.startRecovery();
  
              logger.warn("Worker internal recovery started");
  
              for (WorkerRecoveryListener listener : listeners){
                  try {
                      listener.doRecovery();
                  } catch (Exception ex) {
                      logger.error("Failed on worker internal recovery", ex);
                  }
              }
              if (logger.isDebugEnabled()) logger.debug("Listeners recovery is done");
  
              retryTemplate.retry(RetryTemplate.INFINITELY, 30*1000L, new RetryTemplate.RetryCallback() {
                  @Override
                  public void tryOnce() {
  					if(logger.isDebugEnabled()) logger.debug("sending worker UP");
                      String newWrv = workerNodeService.up(System.getProperty("worker.uuid"), workerVersionService.getWorkerVersion(), workerVersionService.getWorkerVersionId());
                      setWRV(newWrv);
                      if(logger.isDebugEnabled()) logger.debug("the worker is UP");
                  }
              });
              inRecovery = false;
              logger.warn("Worker recovery is done");
          } finally {
              syncManager.finishRecovery();
  		}
  	}
docs: must be volatile since it is read/written in several threads