private void doDeploy(
     Verticle verticle,
     DeploymentOptions options,
     ContextImpl currentContext,
     Handler<AsyncResult<String>> completionHandler) {
   if (options.isMultiThreaded() && !options.isWorker()) {
     throw new IllegalArgumentException("If multi-threaded then must be worker too");
   }
   ContextImpl context =
       options.isWorker()
           ? vertx.createWorkerContext(options.isMultiThreaded())
           : vertx.createEventLoopContext();
   String deploymentID = UUID.randomUUID().toString();
   DeploymentImpl deployment = new DeploymentImpl(deploymentID, context, verticle);
   context.setDeployment(deployment);
   Deployment parent = currentContext.getDeployment();
   if (parent != null) {
     parent.addChild(deployment);
   }
   JsonObject conf = options.getConfig() == null ? null : options.getConfig().copy(); // Copy it
   context.runOnContext(
       v -> {
         try {
           verticle.setVertx(vertx);
           verticle.setConfig(conf);
           verticle.setDeploymentID(deploymentID);
           Future<Void> startFuture = new FutureResultImpl<>();
           verticle.start(startFuture);
           startFuture.setHandler(
               ar -> {
                 if (ar.succeeded()) {
                   deployments.put(deploymentID, deployment);
                   reportSuccess(deploymentID, currentContext, completionHandler);
                 } else {
                   reportFailure(ar.cause(), currentContext, completionHandler);
                 }
               });
         } catch (Throwable t) {
           reportFailure(t, currentContext, completionHandler);
         }
       });
 }
    public void doUndeploy(
        ContextImpl undeployingContext, Handler<AsyncResult<Void>> completionHandler) {

      if (!children.isEmpty()) {
        final int size = children.size();
        AtomicInteger childCount = new AtomicInteger();
        for (Deployment childDeployment : new HashSet<>(children)) {
          childDeployment.doUndeploy(
              undeployingContext,
              ar -> {
                children.remove(childDeployment);
                if (ar.failed()) {
                  reportFailure(ar.cause(), undeployingContext, completionHandler);
                } else if (childCount.incrementAndGet() == size) {
                  // All children undeployed
                  doUndeploy(undeployingContext, completionHandler);
                }
              });
        }
      } else {
        undeployed = true;
        context.runOnContext(
            v -> {
              Future<Void> stopFuture = new FutureResultImpl<>();
              stopFuture.setHandler(
                  ar -> {
                    deployments.remove(id);
                    context.runCloseHooks(
                        ar2 -> {
                          if (ar2.failed()) {
                            // Log error but we report success anyway
                            log.error("Failed to run close hook", ar2.cause());
                          }
                          if (ar.succeeded()) {
                            reportSuccess(null, undeployingContext, completionHandler);
                          } else {
                            reportFailure(ar.cause(), undeployingContext, completionHandler);
                          }
                        });
                  });
              try {
                verticle.stop(stopFuture);
              } catch (Throwable t) {
                stopFuture.setFailure(t);
              }
            });
      }
    }