All Downloads are FREE. Search and download functionalities are using the official Maven repository.

reactor.ipc.netty.tcp.BlockingNettyContext Maven / Gradle / Ivy

There is a newer version: 0.7.15.RELEASE
Show newest version
/*
 * Copyright (c) 2011-2018 Pivotal Software Inc, All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package reactor.ipc.netty.tcp;

import java.net.InetSocketAddress;
import java.time.Duration;
import java.util.concurrent.TimeoutException;

import reactor.core.publisher.Mono;
import reactor.ipc.netty.NettyContext;
import reactor.util.Logger;
import reactor.util.Loggers;

/**
 * Wrap a {@link NettyContext} obtained from a {@link Mono} and offer methods to manage
 * its lifecycle in a blocking fashion.
 *
 * @author Simon Baslé
 */
public class BlockingNettyContext {

	private static final Logger LOG = Loggers.getLogger(BlockingNettyContext.class);

	private final NettyContext context;
	private final String description;

	private Duration lifecycleTimeout;
	private Thread shutdownHook;

	public BlockingNettyContext(Mono contextAsync,
			String description) {
		this(contextAsync, description, Duration.ofSeconds(45));
	}

	public BlockingNettyContext(Mono contextAsync,
			String description, Duration lifecycleTimeout) {
		this.description = description;
		this.lifecycleTimeout = lifecycleTimeout;
		this.context = contextAsync
				.timeout(lifecycleTimeout, Mono.error(new TimeoutException(description + " couldn't be started within " + lifecycleTimeout.toMillis() + "ms")))
				.doOnNext(ctx -> LOG.info("Started {} on {}", description, ctx.address()))
				.block();
	}

	/**
	 * Change the lifecycle timeout applied to the {@link #shutdown()} operation (as this can
	 * only be called AFTER the {@link NettyContext} has been "started").
	 *
	 * @param timeout the new timeout to apply on shutdown.
	 */
	public void setLifecycleTimeout(Duration timeout) {
		this.lifecycleTimeout = timeout;
	}

	/**
	 * Get the {@link NettyContext} wrapped by this facade.
	 * @return the original NettyContext.
	 */
	public NettyContext getContext() {
		return context;
	}

	/**
	 * Return this server's port.
	 * @return The port the server is bound to.
	 */
	public int getPort() {
		return context.address().getPort();
	}

	/**
	 * Return the server's host String. That is, the hostname or in case the server was bound
	 * to a literal IP adress, the IP string representation (rather than performing a reverse-DNS
	 * lookup).
	 *
	 * @return the host string, without reverse DNS lookup
	 * @see NettyContext#address()
	 * @see InetSocketAddress#getHostString()
	 */
	public String getHost() {
		return context.address().getHostString();
	}

	/**
	 * Install a {@link Runtime#addShutdownHook(Thread) JVM shutdown hook} that will
	 * shutdown this {@link BlockingNettyContext} if the JVM is terminated externally.
	 * 

* The hook is removed if shutdown manually, and subsequent calls to this method are * no-op. */ public void installShutdownHook() { //don't return the hook to discourage uninstalling it externally if (this.shutdownHook != null) { return; } this.shutdownHook = new Thread(this::shutdownFromJVM); Runtime.getRuntime().addShutdownHook(this.shutdownHook); } /** * Remove a {@link Runtime#removeShutdownHook(Thread) JVM shutdown hook} if one was * {@link #installShutdownHook() installed} by this {@link BlockingNettyContext}. * * @return true if there was a hook and it was removed, false otherwise. */ public boolean removeShutdownHook() { if (this.shutdownHook != null && Thread.currentThread() != this.shutdownHook) { Thread sdh = this.shutdownHook; this.shutdownHook = null; return Runtime.getRuntime().removeShutdownHook(sdh); } return false; } /** * @return the current JVM shutdown hook. Shouldn't be passed to users. */ protected Thread getShutdownHook() { return this.shutdownHook; } /** * Shut down the {@link NettyContext} and wait for its termination, up to the * {@link #setLifecycleTimeout(Duration) lifecycle timeout}. */ public void shutdown() { if (context.isDisposed()) { return; } removeShutdownHook(); //only applies if not called from the hook's thread context.dispose(); context.onClose() .doOnError(e -> LOG.error("Stopped {} on {} with an error {}", description, context.address(), e)) .doOnTerminate(() -> LOG.info("Stopped {} on {}", description, context.address())) .timeout(lifecycleTimeout, Mono.error(new TimeoutException(description + " couldn't be stopped within " + lifecycleTimeout.toMillis() + "ms"))) .block(); } protected void shutdownFromJVM() { if (context.isDisposed()) { return; } final String hookDesc = Thread.currentThread().toString(); context.dispose(); context.onClose() .doOnError(e -> LOG.error("Stopped {} on {} with an error {} from JVM hook {}", description, context.address(), e, hookDesc)) .doOnTerminate(() -> LOG.info("Stopped {} on {} from JVM hook {}", description, context.address(), hookDesc)) .timeout(lifecycleTimeout, Mono.error(new TimeoutException(description + " couldn't be stopped within " + lifecycleTimeout.toMillis() + "ms"))) .block(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy