vert-x3 / issues

Apache License 2.0
37 stars 7 forks source link

Make Shutdown configurable #121

Closed ObviousDWest closed 3 years ago

ObviousDWest commented 8 years ago

I am using vertx 3.2.1 embedded. And have hit some complications with shutdown... 1) Vertx has a java shutdown hook. It should be able to be removed or nop with a configuration setting, much like Hazelcast provides. 2) Vertx shuts down Hazelcast, even when I pass in a Hazelcast instance using setClusterManager(). Instead, if I pass in the HC instance, I should destroy it the the way I want. 3) I noticed that Vertx close sets a shutdown flag at the beginning of close(). That means if someone else calls close() with a completion handler, it returns immediately, giving the false impression that vertx has cleanly finshed shutting down, when in fact the first call is continuing to undeploy, and then kill hazelcast in parallel. It would be better to delay the completion handler until the real shutdown is complete. Or give an error saying shutdown is in progress but not complete.

A compelling use case for 1) and 2): I'm running in Kubernetes, and when a pod shuts down, it sends a signal to my app, which triggers the shutdown hook. I want a shutdown hook in my app so I can flush some in-memory caches out through vertx event bus to a verticle responsible for doing such things. That means I want to delay vertx shutdown, and Hazelcast shutdown until after the flush. What I had hoped to do was implement my shutdown hook to perform the flush, then undeploy all my verticles, then call vertx.close(), then call hazelcast.shutdown(), in that order.

SercanKaraoglu commented 8 years ago

I had similiar issue, I want to unregister service records from service discovery before shutdown, so that service DOWN message can be published accross the cluster. To solve this issue I added following code to my launcher:


private static Observable<Vertx> createVertx(VertxOptions vertxOptions) {
        if (vertxOptions.isClustered()) {
            HazelcastClusterManager clusterManager = getClusterManager();
            vertxOptions.setClusterManager(clusterManager);
            return Vertx.clusteredVertxObservable(vertxOptions).map(vertx -> {
                clusterManager.getHazelcastInstance().getLifecycleService().addLifecycleListener(state -> {
                    if (state.getState() == LifecycleEvent.LifecycleState.SHUTTING_DOWN) {
                        ICountDownLatch latch = clusterManager.getHazelcastInstance().getCountDownLatch("shutdown.latch");
                        latch.trySetCount(1);
                        beforeLeaveUndeploy(vertx, latch);
                    }
                });
                return vertx;
            });
        } else {
            return Observable.just(Vertx.vertx(vertxOptions)).map(vertx -> {
                Runtime.getRuntime().addShutdownHook(new Thread(() -> beforeLeaveUndeploy(vertx, new CountDownLatch(1))));
                return vertx;
            });
        }
    }

    private static void beforeLeaveUndeploy(Vertx vertx, ICountDownLatch latch) {
        Observable.from(vertx.deploymentIDs().stream().map(vertx::undeployObservable).toArray())
                  .doOnCompleted(latch::countDown)
                  .subscribe();
        try {
            latch.await(30000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

And I do this in Verticle's stop method


@Override public void stop(Future<Void> stopFuture) throws Exception {
        discovery.unpublish(registrationId, r -> {
            if (r.succeeded()) {
                LOGGER.info("Unregistering Service Record With ID {}", registrationId);
                stopFuture.complete(r.result());
            } else {
                LOGGER.error("ERROR unregistering service");
            }

        });
}