From c9298c04bc072ec949776f0cedf5e17c5efe64a2 Mon Sep 17 00:00:00 2001 From: Mikko Karjalainen Date: Tue, 14 Jan 2020 07:39:54 +0000 Subject: [PATCH] Inject Netty executors into Styx Core. (#583) --- .../hotels/styx/client/StyxHttpClient.java | 13 ++- .../client/netty/ClientEventLoopFactory.java | 38 -------- .../NettyConnectionFactory.java | 30 +++---- ...tformAwareClientEventLoopGroupFactory.java | 61 ------------- .../EpollClientEventLoopGroupFactory.java | 57 ------------ .../nio/NioClientEventLoopGroupFactory.java | 57 ------------ components/common/pom.xml | 6 ++ .../com/hotels/styx/EventLoopGroups.java} | 18 +++- .../java/com/hotels/styx/NettyExecutor.java | 88 +++++++++++++++++++ .../com/hotels/styx/StyxPipelineFactory.java | 16 ++-- .../main/java/com/hotels/styx/StyxServer.java | 15 +--- .../hotels/styx/admin/AdminServerBuilder.java | 19 ++-- .../styx/proxy/BackendServicesRouter.java | 16 ++-- .../styx/routing/StaticPipelineFactory.java | 21 ++--- .../routing/handlers/BackendServiceProxy.java | 14 ++- .../styx/routing/handlers/HostProxy.java | 3 +- .../styx/routing/handlers/ProxyToBackend.java | 8 +- .../styx/startup/StyxServerComponents.java | 21 ++--- .../styx/proxy/BackendServicesRouterTest.java | 39 ++++---- .../com/hotels/styx/proxy/StyxProxyTest.java | 20 ++--- .../routing/StaticPipelineBuilderTest.java | 23 +++-- .../com/hotels/styx/server/HttpServers.java | 9 +- .../styx/server/ServerEventLoopFactory.java | 41 --------- .../hotels/styx/server/netty/NettyServer.java | 30 +++---- .../styx/server/netty/NettyServerBuilder.java | 37 ++++---- .../server/netty/NettyServerBuilderSpec.java | 64 -------------- .../netty/connectors/HttpPipelineHandler.java | 17 ++-- .../PlatformAwareServerEventLoopFactory.java | 58 ------------ .../eventloop/ServerEventLoopFactories.java | 67 -------------- .../EpollServerEventLoopGroupFactory.java | 56 ------------ .../eventloop/nio/NioEventLoopGroups.java | 31 ------- .../nio/NioServerEventLoopGroupFactory.java | 55 ------------ .../e2e-suite/src/test/resources/logback.xml | 1 + .../scala/com/hotels/styx/MockServer.scala | 9 +- .../hotels/styx/support/NettyOrigins.scala | 5 +- .../styx/servers/MockOriginServerTest.java | 8 +- .../admin/OriginsFileCompatibilitySpec.kt | 15 +++- 37 files changed, 289 insertions(+), 797 deletions(-) delete mode 100644 components/client/src/main/java/com/hotels/styx/client/netty/ClientEventLoopFactory.java delete mode 100644 components/client/src/main/java/com/hotels/styx/client/netty/eventloop/PlatformAwareClientEventLoopGroupFactory.java delete mode 100644 components/client/src/main/java/com/hotels/styx/client/netty/eventloop/epoll/EpollClientEventLoopGroupFactory.java delete mode 100644 components/client/src/main/java/com/hotels/styx/client/netty/eventloop/nio/NioClientEventLoopGroupFactory.java rename components/{server/src/main/java/com/hotels/styx/server/netty/eventloop/epoll/EpollEventLoopGroups.java => common/src/main/java/com/hotels/styx/EventLoopGroups.java} (64%) create mode 100644 components/common/src/main/java/com/hotels/styx/NettyExecutor.java delete mode 100644 components/server/src/main/java/com/hotels/styx/server/ServerEventLoopFactory.java delete mode 100644 components/server/src/main/java/com/hotels/styx/server/netty/NettyServerBuilderSpec.java delete mode 100644 components/server/src/main/java/com/hotels/styx/server/netty/eventloop/PlatformAwareServerEventLoopFactory.java delete mode 100644 components/server/src/main/java/com/hotels/styx/server/netty/eventloop/ServerEventLoopFactories.java delete mode 100644 components/server/src/main/java/com/hotels/styx/server/netty/eventloop/epoll/EpollServerEventLoopGroupFactory.java delete mode 100644 components/server/src/main/java/com/hotels/styx/server/netty/eventloop/nio/NioEventLoopGroups.java delete mode 100644 components/server/src/main/java/com/hotels/styx/server/netty/eventloop/nio/NioServerEventLoopGroupFactory.java diff --git a/components/client/src/main/java/com/hotels/styx/client/StyxHttpClient.java b/components/client/src/main/java/com/hotels/styx/client/StyxHttpClient.java index cb19167fa4..72f9733963 100644 --- a/components/client/src/main/java/com/hotels/styx/client/StyxHttpClient.java +++ b/components/client/src/main/java/com/hotels/styx/client/StyxHttpClient.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.net.HostAndPort; +import com.hotels.styx.NettyExecutor; import com.hotels.styx.api.HttpRequest; import com.hotels.styx.api.HttpResponse; import com.hotels.styx.api.LiveHttpRequest; @@ -178,6 +179,8 @@ private static Origin originFromRequest(LiveHttpRequest request, Boolean isHttps * Builder for {@link StyxHttpClient}. */ public static class Builder { + private static final NettyExecutor DEFAULT_EXECUTOR = NettyExecutor.create("Styx-Client", 0); + private int connectTimeoutMillis = 1000; private int maxResponseSize = 1024 * 100; private int responseTimeout = 60000; @@ -185,6 +188,7 @@ public static class Builder { private TlsSettings tlsSettings; private boolean isHttps; private String userAgent; + private NettyExecutor executor = DEFAULT_EXECUTOR; public Builder() { } @@ -314,19 +318,24 @@ Builder copy() { return new Builder(this); } + public Builder executor(NettyExecutor executor) { + this.executor = executor; + return this; + } + /** * Construct a client instance. * * @return a new instance */ public StyxHttpClient build() { - NettyConnectionFactory connectionFactory = new NettyConnectionFactory.Builder() .httpConfig(newHttpConfigBuilder().setMaxHeadersSize(maxHeaderSize).build()) .tlsSettings(tlsSettings) .httpRequestOperationFactory(httpRequestOperationFactoryBuilder() .responseTimeoutMillis(responseTimeout) .build()) + .executor(executor) .build(); return new StyxHttpClient(connectionFactory, this.copy()); diff --git a/components/client/src/main/java/com/hotels/styx/client/netty/ClientEventLoopFactory.java b/components/client/src/main/java/com/hotels/styx/client/netty/ClientEventLoopFactory.java deleted file mode 100644 index 0a359322ff..0000000000 --- a/components/client/src/main/java/com/hotels/styx/client/netty/ClientEventLoopFactory.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - Copyright (C) 2013-2018 Expedia Inc. - - 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 com.hotels.styx.client.netty; - -import io.netty.channel.EventLoopGroup; -import io.netty.channel.socket.SocketChannel; - -/** - * A Factory for creating event loops for client workers. - */ -public interface ClientEventLoopFactory { - /** - * Create a new event loop for client workers. - * - * @return a new event loop - */ - EventLoopGroup newClientWorkerEventLoopGroup(); - - /** - * The subclass of {@link SocketChannel} used to create channels. - * - * @return a subclass of {@link SocketChannel} - */ - Class clientSocketChannelClass(); -} diff --git a/components/client/src/main/java/com/hotels/styx/client/netty/connectionpool/NettyConnectionFactory.java b/components/client/src/main/java/com/hotels/styx/client/netty/connectionpool/NettyConnectionFactory.java index ed3eee3a4a..5c8dcf4cf6 100644 --- a/components/client/src/main/java/com/hotels/styx/client/netty/connectionpool/NettyConnectionFactory.java +++ b/components/client/src/main/java/com/hotels/styx/client/netty/connectionpool/NettyConnectionFactory.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ package com.hotels.styx.client.netty.connectionpool; +import com.hotels.styx.NettyExecutor; import com.hotels.styx.api.exceptions.OriginUnreachableException; import com.hotels.styx.api.extension.Origin; import com.hotels.styx.api.extension.service.TlsSettings; @@ -23,14 +24,12 @@ import com.hotels.styx.client.ConnectionSettings; import com.hotels.styx.client.HttpConfig; import com.hotels.styx.client.HttpRequestOperationFactory; -import com.hotels.styx.client.netty.eventloop.PlatformAwareClientEventLoopGroupFactory; import com.hotels.styx.client.ssl.SslContextFactory; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.PooledByteBufAllocator; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; -import io.netty.channel.EventLoopGroup; import io.netty.handler.ssl.SslContext; import reactor.core.publisher.Mono; @@ -48,24 +47,17 @@ * A connection factory that creates connections using netty. */ public class NettyConnectionFactory implements Connection.Factory { - private static final PlatformAwareClientEventLoopGroupFactory FACTORY = new PlatformAwareClientEventLoopGroupFactory( - "Styx-Client-Global", - 0); - private static final Class GLOBAL_CLIENT_EVENT_LOOP_CLASS = FACTORY.clientSocketChannelClass(); - private static final EventLoopGroup GLOBAL_CLIENT_EVENT_LOOP = FACTORY.newClientWorkerEventLoopGroup(); private final HttpConfig httpConfig; private final SslContext sslContext; private final boolean sendSni; private final Optional sniHost; private final HttpRequestOperationFactory httpRequestOperationFactory; + private final NettyExecutor executor; private Bootstrap bootstrap; - private EventLoopGroup eventLoopGroup; - private Class clientSocketChannelClass; private NettyConnectionFactory(Builder builder) { - this.clientSocketChannelClass = requireNonNull(builder.channelClass); - this.eventLoopGroup = requireNonNull(builder.eventLoopGroup); + this.executor = requireNonNull(builder.executor); this.httpConfig = requireNonNull(builder.httpConfig); this.sslContext = builder.tlsSettings == null ? null : SslContextFactory.get(builder.tlsSettings); this.httpRequestOperationFactory = requireNonNull(builder.httpRequestOperationFactory); @@ -101,8 +93,8 @@ private ChannelFuture openConnection(Origin origin, ConnectionSettings connectio private synchronized void bootstrap(ConnectionSettings connectionSettings) { if (bootstrap == null) { bootstrap = new Bootstrap(); - bootstrap.group(eventLoopGroup) - .channel(clientSocketChannelClass) + bootstrap.group(executor.eventLoopGroup()) + .channel(executor.clientEventLoopClass()) .handler(new Initializer()) .option(TCP_NODELAY, true) .option(SO_KEEPALIVE, true) @@ -124,15 +116,15 @@ protected void initChannel(Channel ch) { * Builder. */ public static final class Builder { + private static final NettyExecutor DEFAULT_EXECUTOR = NettyExecutor.create("Netty-Executor", 0); + private HttpRequestOperationFactory httpRequestOperationFactory = httpRequestOperationFactoryBuilder().build(); private HttpConfig httpConfig = defaultHttpConfig(); private TlsSettings tlsSettings; - private EventLoopGroup eventLoopGroup = GLOBAL_CLIENT_EVENT_LOOP; - private Class channelClass = GLOBAL_CLIENT_EVENT_LOOP_CLASS; + private NettyExecutor executor = DEFAULT_EXECUTOR; - public Builder nettyEventLoop(EventLoopGroup eventLoopGroup, Class channelClass) { - this.eventLoopGroup = requireNonNull(eventLoopGroup); - this.channelClass = requireNonNull(channelClass); + public Builder executor(NettyExecutor executor) { + this.executor = executor; return this; } diff --git a/components/client/src/main/java/com/hotels/styx/client/netty/eventloop/PlatformAwareClientEventLoopGroupFactory.java b/components/client/src/main/java/com/hotels/styx/client/netty/eventloop/PlatformAwareClientEventLoopGroupFactory.java deleted file mode 100644 index a7c45c5baf..0000000000 --- a/components/client/src/main/java/com/hotels/styx/client/netty/eventloop/PlatformAwareClientEventLoopGroupFactory.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - Copyright (C) 2013-2018 Expedia Inc. - - 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 com.hotels.styx.client.netty.eventloop; - -import com.hotels.styx.client.netty.ClientEventLoopFactory; -import com.hotels.styx.client.netty.eventloop.epoll.EpollClientEventLoopGroupFactory; -import com.hotels.styx.client.netty.eventloop.nio.NioClientEventLoopGroupFactory; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.epoll.Epoll; -import io.netty.channel.socket.SocketChannel; -import org.slf4j.Logger; - -import static org.slf4j.LoggerFactory.getLogger; - -/** - * A factory that creates platform-aware client event loops. - */ -public class PlatformAwareClientEventLoopGroupFactory implements ClientEventLoopFactory { - private static final Logger LOG = getLogger(PlatformAwareClientEventLoopGroupFactory.class); - - private final ClientEventLoopFactory delegate; - - /** - * Creates a new factory. - * - * @param name name to attach to threads - * @param clientWorkerThreadsCount number of threads - */ - public PlatformAwareClientEventLoopGroupFactory(String name, int clientWorkerThreadsCount) { - if (Epoll.isAvailable()) { - LOG.info("Epoll is available so using the native socket transport."); - delegate = new EpollClientEventLoopGroupFactory(name, clientWorkerThreadsCount); - } else { - LOG.info("Epoll not available Using nio socket transport."); - delegate = new NioClientEventLoopGroupFactory(name, clientWorkerThreadsCount); - } - } - - @Override - public EventLoopGroup newClientWorkerEventLoopGroup() { - return delegate.newClientWorkerEventLoopGroup(); - } - - @Override - public Class clientSocketChannelClass() { - return delegate.clientSocketChannelClass(); - } -} diff --git a/components/client/src/main/java/com/hotels/styx/client/netty/eventloop/epoll/EpollClientEventLoopGroupFactory.java b/components/client/src/main/java/com/hotels/styx/client/netty/eventloop/epoll/EpollClientEventLoopGroupFactory.java deleted file mode 100644 index 3cda2bfb38..0000000000 --- a/components/client/src/main/java/com/hotels/styx/client/netty/eventloop/epoll/EpollClientEventLoopGroupFactory.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - Copyright (C) 2013-2019 Expedia Inc. - - 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 com.hotels.styx.client.netty.eventloop.epoll; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import com.hotels.styx.client.netty.ClientEventLoopFactory; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.epoll.EpollEventLoopGroup; -import io.netty.channel.epoll.EpollSocketChannel; -import io.netty.channel.socket.SocketChannel; - -import static com.hotels.styx.common.Preconditions.checkArgument; -import static com.hotels.styx.common.Preconditions.checkNotEmpty; - -/** - * A factory for creating Epoll-based client event loops. - */ -public class EpollClientEventLoopGroupFactory implements ClientEventLoopFactory { - private final String name; - private final int clientWorkerThreadsCount; - - /** - * Creates a factory. - * - * @param name name to attach to threads - * @param clientWorkerThreadsCount number of threads - */ - public EpollClientEventLoopGroupFactory(String name, int clientWorkerThreadsCount) { - this.name = checkNotEmpty(name); - this.clientWorkerThreadsCount = checkArgument(clientWorkerThreadsCount, clientWorkerThreadsCount > -1); - } - - @Override - public EventLoopGroup newClientWorkerEventLoopGroup() { - return new EpollEventLoopGroup(clientWorkerThreadsCount, new ThreadFactoryBuilder() - .setNameFormat(name + "-Client-Worker-%d-Thread") - .build()); - } - - @Override - public Class clientSocketChannelClass() { - return EpollSocketChannel.class; - } -} diff --git a/components/client/src/main/java/com/hotels/styx/client/netty/eventloop/nio/NioClientEventLoopGroupFactory.java b/components/client/src/main/java/com/hotels/styx/client/netty/eventloop/nio/NioClientEventLoopGroupFactory.java deleted file mode 100644 index daf2b00d21..0000000000 --- a/components/client/src/main/java/com/hotels/styx/client/netty/eventloop/nio/NioClientEventLoopGroupFactory.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - Copyright (C) 2013-2018 Expedia Inc. - - 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 com.hotels.styx.client.netty.eventloop.nio; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import com.hotels.styx.client.netty.ClientEventLoopFactory; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioSocketChannel; - -import static java.util.Objects.requireNonNull; - - -/** - * A factory for creating non-blocking-I/O-based client event loops. - */ -public class NioClientEventLoopGroupFactory implements ClientEventLoopFactory { - private final String name; - private final int clientWorkerThreadsCount; - - /** - * Constructs an instance. - * - * @param name name to prefix thread names with - * @param clientWorkerThreadsCount number of client worker threads - */ - public NioClientEventLoopGroupFactory(String name, int clientWorkerThreadsCount) { - this.name = requireNonNull(name); - this.clientWorkerThreadsCount = requireNonNull(clientWorkerThreadsCount); - } - - @Override - public EventLoopGroup newClientWorkerEventLoopGroup() { - return new NioEventLoopGroup(clientWorkerThreadsCount, new ThreadFactoryBuilder() - .setNameFormat(name + "-Client-Worker-%d-Thread") - .build()); - } - - @Override - public Class clientSocketChannelClass() { - return NioSocketChannel.class; - } -} diff --git a/components/common/pom.xml b/components/common/pom.xml index 3ac4314bb3..5a7d975600 100644 --- a/components/common/pom.xml +++ b/components/common/pom.xml @@ -20,6 +20,12 @@ styx-api + + io.netty + netty-transport-native-epoll + ${netty-transport-native-epoll.classifier} + + io.projectreactor reactor-core diff --git a/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/epoll/EpollEventLoopGroups.java b/components/common/src/main/java/com/hotels/styx/EventLoopGroups.java similarity index 64% rename from components/server/src/main/java/com/hotels/styx/server/netty/eventloop/epoll/EpollEventLoopGroups.java rename to components/common/src/main/java/com/hotels/styx/EventLoopGroups.java index 4e743429df..b34f3c4612 100644 --- a/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/epoll/EpollEventLoopGroups.java +++ b/components/common/src/main/java/com/hotels/styx/EventLoopGroups.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2018 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,14 +13,24 @@ See the License for the specific language governing permissions and limitations under the License. */ -package com.hotels.styx.server.netty.eventloop.epoll; +package com.hotels.styx; import com.google.common.util.concurrent.ThreadFactoryBuilder; import io.netty.channel.EventLoopGroup; import io.netty.channel.epoll.EpollEventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; -class EpollEventLoopGroups { - public static EventLoopGroup newEventLoopGroup(int threadsCount, String threadsNameFormat) { +final class EventLoopGroups { + private EventLoopGroups() { + } + + public static EventLoopGroup nioEventLoopGroup(int threadsCount, String threadsNameFormat) { + return new NioEventLoopGroup(threadsCount, new ThreadFactoryBuilder() + .setNameFormat(threadsNameFormat) + .build()); + } + + public static EventLoopGroup epollEventLoopGroup(int threadsCount, String threadsNameFormat) { return new EpollEventLoopGroup(threadsCount, new ThreadFactoryBuilder() .setNameFormat(threadsNameFormat) .build()); diff --git a/components/common/src/main/java/com/hotels/styx/NettyExecutor.java b/components/common/src/main/java/com/hotels/styx/NettyExecutor.java new file mode 100644 index 0000000000..160a54cec3 --- /dev/null +++ b/components/common/src/main/java/com/hotels/styx/NettyExecutor.java @@ -0,0 +1,88 @@ +/* + Copyright (C) 2013-2020 Expedia Inc. + + 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 com.hotels.styx; + +import io.netty.channel.EventLoopGroup; +import io.netty.channel.ServerChannel; +import io.netty.channel.epoll.Epoll; +import io.netty.channel.epoll.EpollServerSocketChannel; +import io.netty.channel.epoll.EpollSocketChannel; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static com.hotels.styx.EventLoopGroups.epollEventLoopGroup; +import static com.hotels.styx.EventLoopGroups.nioEventLoopGroup; + +/** + * A netty based executor for styx. + */ +public class NettyExecutor { + private static final Logger LOG = LoggerFactory.getLogger(NettyExecutor.class); + + private final Class serverEventLoopClass; + private final Class clientEventLoopClass; + private final EventLoopGroup eventLoopGroup; + + /** + * Constructs an netty/io event executor. + * @param name thread group name. + * @param count thread count. + * @return + */ + public static NettyExecutor create(String name, int count) { + if (Epoll.isAvailable()) { + LOG.info("Epoll is available. Using the native socket transport."); + return new NettyExecutor( + epollEventLoopGroup(count, name + "-%d-Thread"), + EpollServerSocketChannel.class, + EpollSocketChannel.class); + } else { + LOG.info("Epoll not available. Using nio socket transport."); + return new NettyExecutor( + nioEventLoopGroup(count, name + "-%d-Thread"), + NioServerSocketChannel.class, + NioSocketChannel.class); + } + } + + private NettyExecutor(EventLoopGroup eventLoopGroup, + Class serverEventLoopClass, + Class clientEventLoopClass) { + this.serverEventLoopClass = serverEventLoopClass; + this.clientEventLoopClass = clientEventLoopClass; + this.eventLoopGroup = eventLoopGroup; + } + + public void shut() { + eventLoopGroup.shutdownGracefully(); + } + + public Class serverEventLoopClass() { + return serverEventLoopClass; + } + + public Class clientEventLoopClass() { + return clientEventLoopClass; + } + + public EventLoopGroup eventLoopGroup() { + return eventLoopGroup; + } + +} diff --git a/components/proxy/src/main/java/com/hotels/styx/StyxPipelineFactory.java b/components/proxy/src/main/java/com/hotels/styx/StyxPipelineFactory.java index ecd22159be..ffdf59544b 100644 --- a/components/proxy/src/main/java/com/hotels/styx/StyxPipelineFactory.java +++ b/components/proxy/src/main/java/com/hotels/styx/StyxPipelineFactory.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,8 +28,6 @@ import com.hotels.styx.routing.config.Builtins; import com.hotels.styx.routing.config.RoutingObjectFactory; import com.hotels.styx.routing.handlers.HttpInterceptorPipeline; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.socket.SocketChannel; import java.util.List; import java.util.Map; @@ -48,8 +46,7 @@ public class StyxPipelineFactory { private final Environment environment; private final Map services; private final List plugins; - private final EventLoopGroup eventLoopGroup; - private final Class nettySocketChannelClass; + private final NettyExecutor executor; public StyxPipelineFactory( @@ -57,14 +54,12 @@ public StyxPipelineFactory( Environment environment, Map services, List plugins, - EventLoopGroup eventLoopGroup, - Class nettySocketChannelClass) { + NettyExecutor executor) { this.builtinRoutingObjects = requireNonNull(builtinRoutingObjects); this.environment = requireNonNull(environment); this.services = requireNonNull(services); this.plugins = requireNonNull(plugins); - this.eventLoopGroup = requireNonNull(eventLoopGroup); - this.nettySocketChannelClass = requireNonNull(nettySocketChannelClass); + this.executor = requireNonNull(executor); } public HttpHandler create() { @@ -90,8 +85,7 @@ private RoutingObject configuredPipeline(RoutingObjectFactory.Context routingObj environment, registry != null ? registry : new MemoryBackedRegistry<>(), plugins, - eventLoopGroup, - nettySocketChannelClass, + executor, requestTracking) .build(); } diff --git a/components/proxy/src/main/java/com/hotels/styx/StyxServer.java b/components/proxy/src/main/java/com/hotels/styx/StyxServer.java index f383e144b5..45a9bc531e 100644 --- a/components/proxy/src/main/java/com/hotels/styx/StyxServer.java +++ b/components/proxy/src/main/java/com/hotels/styx/StyxServer.java @@ -32,11 +32,8 @@ import com.hotels.styx.proxy.plugin.NamedPlugin; import com.hotels.styx.server.ConnectorConfig; import com.hotels.styx.server.HttpServer; -import com.hotels.styx.server.ServerEventLoopFactory; import com.hotels.styx.server.netty.NettyServerBuilder; -import com.hotels.styx.server.netty.NettyServerConfig; import com.hotels.styx.server.netty.ServerConnector; -import com.hotels.styx.server.netty.eventloop.PlatformAwareServerEventLoopFactory; import com.hotels.styx.startup.StyxServerComponents; import io.netty.util.ResourceLeakDetector; import org.jetbrains.annotations.NotNull; @@ -55,7 +52,6 @@ import static com.hotels.styx.infrastructure.logging.LOGBackConfigurer.initLogging; import static com.hotels.styx.infrastructure.logging.LOGBackConfigurer.shutdownLogging; import static com.hotels.styx.proxy.encoders.ConfigurableUnwiseCharsEncoder.ENCODE_UNWISECHARS; -import static com.hotels.styx.server.netty.eventloop.ServerEventLoopFactories.memoize; import static com.hotels.styx.startup.CoreMetrics.registerCoreMetrics; import static io.netty.util.ResourceLeakDetector.Level.DISABLED; import static java.lang.Runtime.getRuntime; @@ -180,8 +176,7 @@ public StyxServer(StyxServerComponents components, Stopwatch stopwatch) { components.environment(), components.services(), components.plugins(), - components.eventLoopGroup(), - components.nettySocketChannelClass()) + components.clientExecutor()) .create(); // Startup phase 1: start plugins, control plane providers, and other services: @@ -230,11 +225,6 @@ public InetSocketAddress adminHttpAddress() { return adminServer.inetAddress(); } - // This function will be removed in near future: - private static ServerEventLoopFactory serverEventLoopFactory(String name, NettyServerConfig serverConfig) { - return memoize(new PlatformAwareServerEventLoopFactory(name, serverConfig.bossThreadsCount(), serverConfig.workerThreadsCount())); - } - private static HttpServer httpServer(Environment environment, ConnectorConfig connectorConfig, HttpHandler styxDataPlane) { CharSequence styxInfoHeaderName = environment.configuration().styxHeaderConfig().styxInfoHeaderName(); ResponseInfoFormat responseInfoFormat = new ResponseInfoFormat(environment); @@ -250,7 +240,8 @@ private static HttpServer httpServer(Environment environment, ConnectorConfig co return NettyServerBuilder.newBuilder() .setMetricsRegistry(environment.metricRegistry()) - .setServerEventLoopFactory(serverEventLoopFactory("Proxy", environment.configuration().proxyServerConfig())) + .bossExecutor(NettyExecutor.create("Proxy-Boss", environment.configuration().proxyServerConfig().bossThreadsCount())) + .workerExecutor(NettyExecutor.create("Proxy-Worker", environment.configuration().proxyServerConfig().workerThreadsCount())) .setProtocolConnector(proxyConnector) .handler(styxDataPlane) .build(); diff --git a/components/proxy/src/main/java/com/hotels/styx/admin/AdminServerBuilder.java b/components/proxy/src/main/java/com/hotels/styx/admin/AdminServerBuilder.java index 408edeb2c2..fc414e46e8 100644 --- a/components/proxy/src/main/java/com/hotels/styx/admin/AdminServerBuilder.java +++ b/components/proxy/src/main/java/com/hotels/styx/admin/AdminServerBuilder.java @@ -18,6 +18,7 @@ import com.codahale.metrics.json.MetricsModule; import com.google.common.collect.ImmutableList; import com.hotels.styx.Environment; +import com.hotels.styx.NettyExecutor; import com.hotels.styx.StartupConfig; import com.hotels.styx.StyxConfig; import com.hotels.styx.admin.dashboard.DashboardData; @@ -59,7 +60,7 @@ import com.hotels.styx.server.AdminHttpRouter; import com.hotels.styx.server.HttpServer; import com.hotels.styx.server.handlers.ClassPathResourceHandler; -import com.hotels.styx.server.netty.NettyServerBuilderSpec; +import com.hotels.styx.server.netty.NettyServerBuilder; import com.hotels.styx.server.netty.WebServerConnectorFactory; import com.hotels.styx.server.track.CurrentRequestTracker; import com.hotels.styx.startup.StyxServerComponents; @@ -119,10 +120,18 @@ public HttpServer build() { StyxConfig styxConfig = environment.configuration(); AdminServerConfig adminServerConfig = styxConfig.adminServerConfig(); - return new NettyServerBuilderSpec("Admin", environment.serverEnvironment(), new WebServerConnectorFactory()) - .toNettyServerBuilder(adminServerConfig) - .handler(adminEndpoints(styxConfig, startupConfig)) - .build(); + NettyExecutor executor = NettyExecutor.create("Admin-Boss", adminServerConfig.bossThreadsCount()); + NettyServerBuilder builder = NettyServerBuilder.newBuilder() + .setMetricsRegistry(environment.metricRegistry()) + .bossExecutor(executor) + .workerExecutor(NettyExecutor.create("Admin-Worker", adminServerConfig.workerThreadsCount())) + .handler(adminEndpoints(styxConfig, startupConfig)); + + // Currently admin server cannot be started over TLS protocol. + // This appears to be an existing issue that needs rectifying. + adminServerConfig.httpConnectorConfig().ifPresent(it -> builder.setProtocolConnector(new WebServerConnectorFactory().create(it))); + + return builder.build(); } private HttpHandler adminEndpoints(StyxConfig styxConfig, StartupConfig startupConfig) { diff --git a/components/proxy/src/main/java/com/hotels/styx/proxy/BackendServicesRouter.java b/components/proxy/src/main/java/com/hotels/styx/proxy/BackendServicesRouter.java index 320ae0d69b..f3a55e6190 100644 --- a/components/proxy/src/main/java/com/hotels/styx/proxy/BackendServicesRouter.java +++ b/components/proxy/src/main/java/com/hotels/styx/proxy/BackendServicesRouter.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package com.hotels.styx.proxy; import com.hotels.styx.Environment; +import com.hotels.styx.NettyExecutor; import com.hotels.styx.api.Eventual; import com.hotels.styx.api.HttpHandler; import com.hotels.styx.api.HttpInterceptor; @@ -43,8 +44,6 @@ import com.hotels.styx.client.healthcheck.UrlRequestHealthCheck; import com.hotels.styx.client.netty.connectionpool.NettyConnectionFactory; import com.hotels.styx.server.HttpRouter; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.socket.SocketChannel; import org.slf4j.Logger; import java.util.Map; @@ -68,18 +67,15 @@ public class BackendServicesRouter implements HttpRouter, Registry.ChangeListene private final BackendServiceClientFactory clientFactory; private final Environment environment; - private final EventLoopGroup nettyEventLoopGroup; - private final Class socketChannelClass; + private final NettyExecutor executor; private final ConcurrentMap routes; public BackendServicesRouter(BackendServiceClientFactory clientFactory, Environment environment, - EventLoopGroup nettyEventLoopGroup, - Class socketChannelClass) { + NettyExecutor executor) { this.clientFactory = requireNonNull(clientFactory); this.environment = requireNonNull(environment); - this.nettyEventLoopGroup = requireNonNull(nettyEventLoopGroup); - this.socketChannelClass = requireNonNull(socketChannelClass); + this.executor = requireNonNull(executor); this.routes = new ConcurrentSkipListMap<>( comparingInt(String::length).reversed() @@ -184,7 +180,7 @@ private Connection.Factory connectionFactory( long connectionExpiration) { Connection.Factory factory = new NettyConnectionFactory.Builder() - .nettyEventLoop(nettyEventLoopGroup, socketChannelClass) + .executor(executor) .httpRequestOperationFactory( httpRequestOperationFactoryBuilder() .flowControlEnabled(true) diff --git a/components/proxy/src/main/java/com/hotels/styx/routing/StaticPipelineFactory.java b/components/proxy/src/main/java/com/hotels/styx/routing/StaticPipelineFactory.java index b9a5e9e5d5..450907e177 100644 --- a/components/proxy/src/main/java/com/hotels/styx/routing/StaticPipelineFactory.java +++ b/components/proxy/src/main/java/com/hotels/styx/routing/StaticPipelineFactory.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ import com.google.common.annotations.VisibleForTesting; import com.hotels.styx.Environment; +import com.hotels.styx.NettyExecutor; import com.hotels.styx.api.extension.service.BackendService; import com.hotels.styx.api.extension.service.spi.Registry; import com.hotels.styx.proxy.BackendServiceClientFactory; @@ -25,8 +26,6 @@ import com.hotels.styx.proxy.RouteHandlerAdapter; import com.hotels.styx.proxy.StyxBackendServiceClientFactory; import com.hotels.styx.proxy.plugin.NamedPlugin; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.socket.SocketChannel; import static java.util.Objects.requireNonNull; @@ -39,8 +38,7 @@ public class StaticPipelineFactory { private final Environment environment; private final Registry registry; private final Iterable plugins; - private final EventLoopGroup eventLoopGroup; - private final Class nettySocketChannelClass; + private final NettyExecutor executor; private final boolean trackRequests; @VisibleForTesting @@ -48,25 +46,22 @@ public class StaticPipelineFactory { Environment environment, Registry registry, Iterable plugins, - EventLoopGroup eventLoopGroup, - Class nettySocketChannelClass, + NettyExecutor executor, boolean trackRequests) { this.clientFactory = requireNonNull(clientFactory); this.environment = requireNonNull(environment); this.registry = requireNonNull(registry); this.plugins = requireNonNull(plugins); - this.eventLoopGroup = requireNonNull(eventLoopGroup); - this.nettySocketChannelClass = requireNonNull(nettySocketChannelClass); + this.executor = requireNonNull(executor); this.trackRequests = trackRequests; } public StaticPipelineFactory(Environment environment, Registry registry, Iterable plugins, - EventLoopGroup eventLoopGroup, - Class nettySocketChannelClass, + NettyExecutor executor, boolean trackRequests) { - this(createClientFactory(environment), environment, registry, plugins, eventLoopGroup, nettySocketChannelClass, trackRequests); + this(createClientFactory(environment), environment, registry, plugins, executor, trackRequests); } private static BackendServiceClientFactory createClientFactory(Environment environment) { @@ -74,7 +69,7 @@ private static BackendServiceClientFactory createClientFactory(Environment envir } public RoutingObject build() { - BackendServicesRouter backendServicesRouter = new BackendServicesRouter(clientFactory, environment, eventLoopGroup, nettySocketChannelClass); + BackendServicesRouter backendServicesRouter = new BackendServicesRouter(clientFactory, environment, executor); registry.addListener(backendServicesRouter); RouteHandlerAdapter router = new RouteHandlerAdapter(backendServicesRouter); diff --git a/components/proxy/src/main/java/com/hotels/styx/routing/handlers/BackendServiceProxy.java b/components/proxy/src/main/java/com/hotels/styx/routing/handlers/BackendServiceProxy.java index d74375c612..b8e6c91fa1 100644 --- a/components/proxy/src/main/java/com/hotels/styx/routing/handlers/BackendServiceProxy.java +++ b/components/proxy/src/main/java/com/hotels/styx/routing/handlers/BackendServiceProxy.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,13 +17,13 @@ import com.google.common.annotations.VisibleForTesting; import com.hotels.styx.Environment; +import com.hotels.styx.NettyExecutor; import com.hotels.styx.api.Eventual; import com.hotels.styx.api.HttpInterceptor; import com.hotels.styx.api.LiveHttpRequest; import com.hotels.styx.api.LiveHttpResponse; import com.hotels.styx.api.extension.service.BackendService; import com.hotels.styx.api.extension.service.spi.Registry; -import com.hotels.styx.client.netty.eventloop.PlatformAwareClientEventLoopGroupFactory; import com.hotels.styx.infrastructure.configuration.yaml.JsonNodeConfig; import com.hotels.styx.proxy.BackendServiceClientFactory; import com.hotels.styx.proxy.BackendServicesRouter; @@ -32,8 +32,6 @@ import com.hotels.styx.routing.RoutingObject; import com.hotels.styx.routing.config.RoutingObjectFactory; import com.hotels.styx.routing.config.StyxObjectDefinition; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.socket.SocketChannel; import java.util.List; import java.util.Map; @@ -58,9 +56,8 @@ private BackendServiceProxy( BackendServiceClientFactory serviceClientFactory, Registry registry, Environment environment, - EventLoopGroup eventLoopGroup, - Class nettySocketChannelClass) { - BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, eventLoopGroup, nettySocketChannelClass); + NettyExecutor executor) { + BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, executor); registry.addListener(router); handler = new RouteHandlerAdapter(router); } @@ -108,8 +105,7 @@ public RoutingObject build(List fullName, Context context, StyxObjectDef join(".", append(fullName, "backendProvider")), provider)); } - PlatformAwareClientEventLoopGroupFactory factory = new PlatformAwareClientEventLoopGroupFactory("BackendServiceProxy", 0); - return new BackendServiceProxy(serviceClientFactory, registry, environment, factory.newClientWorkerEventLoopGroup(), factory.clientSocketChannelClass()); + return new BackendServiceProxy(serviceClientFactory, registry, environment, NettyExecutor.create("BackendServiceProxy", 0)); } } diff --git a/components/proxy/src/main/java/com/hotels/styx/routing/handlers/HostProxy.java b/components/proxy/src/main/java/com/hotels/styx/routing/handlers/HostProxy.java index 10fbdb6b6f..711e3a95d7 100644 --- a/components/proxy/src/main/java/com/hotels/styx/routing/handlers/HostProxy.java +++ b/components/proxy/src/main/java/com/hotels/styx/routing/handlers/HostProxy.java @@ -127,7 +127,7 @@ public Eventual handle(LiveHttpRequest request, HttpIntercepto if (active) { return new Eventual<>( ResponseEventListener.from(client.sendRequest(request)) - .whenCancelled(() -> originMetrics.requestCancelled()) + .whenCancelled(originMetrics::requestCancelled) .apply()); } else { return Eventual.error(new IllegalStateException(errorMessage)); @@ -283,6 +283,7 @@ private static Connection.Factory connectionFactory( OriginStatsFactory originStatsFactory, long connectionExpiration) { + // Uses the default executor for now: NettyConnectionFactory factory = new NettyConnectionFactory.Builder() .httpRequestOperationFactory( httpRequestOperationFactoryBuilder() diff --git a/components/proxy/src/main/java/com/hotels/styx/routing/handlers/ProxyToBackend.java b/components/proxy/src/main/java/com/hotels/styx/routing/handlers/ProxyToBackend.java index b531922f90..9dfdcbfc95 100644 --- a/components/proxy/src/main/java/com/hotels/styx/routing/handlers/ProxyToBackend.java +++ b/components/proxy/src/main/java/com/hotels/styx/routing/handlers/ProxyToBackend.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.google.common.annotations.VisibleForTesting; +import com.hotels.styx.NettyExecutor; import com.hotels.styx.api.Eventual; import com.hotels.styx.api.HttpInterceptor; import com.hotels.styx.api.LiveHttpRequest; @@ -32,7 +33,6 @@ import com.hotels.styx.client.connectionpool.ExpiringConnectionFactory; import com.hotels.styx.client.connectionpool.SimpleConnectionPoolFactory; import com.hotels.styx.client.netty.connectionpool.NettyConnectionFactory; -import com.hotels.styx.client.netty.eventloop.PlatformAwareClientEventLoopGroupFactory; import com.hotels.styx.config.schema.Schema; import com.hotels.styx.infrastructure.configuration.yaml.JsonNodeConfig; import com.hotels.styx.proxy.BackendServiceClientFactory; @@ -99,10 +99,8 @@ static RoutingObject build(List parents, Context context, StyxObjectDefi OriginStatsFactory originStatsFactory = new CachingOriginStatsFactory(context.environment().metricRegistry()); - PlatformAwareClientEventLoopGroupFactory factory = new PlatformAwareClientEventLoopGroupFactory("Styx", clientWorkerThreadsCount); - Connection.Factory connectionFactory = new NettyConnectionFactory.Builder() - .nettyEventLoop(factory.newClientWorkerEventLoopGroup(), factory.clientSocketChannelClass()) + .executor(NettyExecutor.create("Styx", clientWorkerThreadsCount)) .httpRequestOperationFactory( httpRequestOperationFactoryBuilder() .flowControlEnabled(true) diff --git a/components/proxy/src/main/java/com/hotels/styx/startup/StyxServerComponents.java b/components/proxy/src/main/java/com/hotels/styx/startup/StyxServerComponents.java index b8246d1c28..5fb72f45aa 100644 --- a/components/proxy/src/main/java/com/hotels/styx/startup/StyxServerComponents.java +++ b/components/proxy/src/main/java/com/hotels/styx/startup/StyxServerComponents.java @@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.AsyncEventBus; import com.hotels.styx.Environment; +import com.hotels.styx.NettyExecutor; import com.hotels.styx.StartupConfig; import com.hotels.styx.StyxConfig; import com.hotels.styx.Version; @@ -30,7 +31,6 @@ import com.hotels.styx.api.extension.service.spi.StyxService; import com.hotels.styx.api.metrics.codahale.CodaHaleMetricRegistry; import com.hotels.styx.api.plugins.spi.Plugin; -import com.hotels.styx.client.netty.eventloop.PlatformAwareClientEventLoopGroupFactory; import com.hotels.styx.common.format.SanitisedHttpHeaderFormatter; import com.hotels.styx.common.format.SanitisedHttpMessageFormatter; import com.hotels.styx.infrastructure.configuration.yaml.JsonNodeConfig; @@ -43,8 +43,6 @@ import com.hotels.styx.routing.handlers.RouteRefLookup.RouteDbRefLookup; import com.hotels.styx.routing.handlers.StyxObjectRecord; import com.hotels.styx.startup.extensions.ConfiguredPluginFactory; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.socket.SocketChannel; import org.slf4j.Logger; import java.util.HashMap; @@ -75,13 +73,12 @@ public class StyxServerComponents { private final List plugins; private final StyxObjectStore routeObjectStore = new StyxObjectStore<>(); private final StyxObjectStore> providerObjectStore = new StyxObjectStore<>(); - private final EventLoopGroup eventLoopGroup; - private final Class nettySocketChannelClass; private final RoutingObjectFactory.Context routingObjectContext; private final StartupConfig startupConfig; private final Map routingObjectFactories; private static final Logger LOGGER = getLogger(StyxServerComponents.class); + private final NettyExecutor executor; private StyxServerComponents(Builder builder) { StyxConfig styxConfig = requireNonNull(builder.styxConfig); @@ -95,12 +92,7 @@ private StyxServerComponents(Builder builder) { this.environment = newEnvironment(styxConfig, builder.metricRegistry); builder.loggingSetUp.setUp(environment); - PlatformAwareClientEventLoopGroupFactory factory = new PlatformAwareClientEventLoopGroupFactory( - "Styx", - environment.configuration().proxyServerConfig().clientWorkerThreadsCount()); - - this.eventLoopGroup = factory.newClientWorkerEventLoopGroup(); - this.nettySocketChannelClass = factory.clientSocketChannelClass(); + this.executor = NettyExecutor.create("Styx-Client-Worker", environment.configuration().proxyServerConfig().clientWorkerThreadsCount()); // TODO In further refactoring, we will probably want this loading to happen outside of this constructor call, // so that it doesn't delay the admin server from starting up @@ -191,12 +183,9 @@ public RoutingObjectFactory.Context routingObjectFactoryContext() { return this.routingObjectContext; } - public EventLoopGroup eventLoopGroup() { - return this.eventLoopGroup; - } - public Class nettySocketChannelClass() { - return this.nettySocketChannelClass; + public NettyExecutor clientExecutor() { + return this.executor; } public StartupConfig startupConfig() { diff --git a/components/proxy/src/test/java/com/hotels/styx/proxy/BackendServicesRouterTest.java b/components/proxy/src/test/java/com/hotels/styx/proxy/BackendServicesRouterTest.java index a9cc391f2a..fe49141931 100644 --- a/components/proxy/src/test/java/com/hotels/styx/proxy/BackendServicesRouterTest.java +++ b/components/proxy/src/test/java/com/hotels/styx/proxy/BackendServicesRouterTest.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package com.hotels.styx.proxy; import com.hotels.styx.Environment; +import com.hotels.styx.NettyExecutor; import com.hotels.styx.api.HttpHandler; import com.hotels.styx.api.HttpInterceptor; import com.hotels.styx.api.LiveHttpRequest; @@ -26,11 +27,7 @@ import com.hotels.styx.client.BackendServiceClient; import com.hotels.styx.client.OriginStatsFactory; import com.hotels.styx.client.OriginsInventory; -import com.hotels.styx.client.netty.ClientEventLoopFactory; -import com.hotels.styx.client.netty.eventloop.PlatformAwareClientEventLoopGroupFactory; import com.hotels.styx.server.HttpInterceptorContext; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.socket.SocketChannel; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -70,13 +67,11 @@ public class BackendServicesRouterTest { private Environment environment; - private ClientEventLoopFactory factory = new PlatformAwareClientEventLoopGroupFactory("x", 0); - private EventLoopGroup eventLoopGroup = this.factory.newClientWorkerEventLoopGroup(); - private Class channelClass = this.factory.clientSocketChannelClass(); + private NettyExecutor executor = NettyExecutor.create("x", 1); @AfterAll public void tearDown() { - eventLoopGroup.shutdown(); + executor.shut(); } @BeforeEach @@ -91,7 +86,7 @@ public void registersAllRoutes() { appB().newCopy().path("/badheaders").build(), appB().newCopy().id("appB-03").path("/cookies").build()); - BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, eventLoopGroup, channelClass); + BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, executor); router.onChange(changes); assertThat(router.routes().keySet(), contains("/badheaders", "/cookies", "/headers")); @@ -103,7 +98,7 @@ public void selectsServiceBasedOnPath() throws Exception { appA().newCopy().path("/").build(), appB().newCopy().path("/appB/hotel/details.html").build()); - BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, eventLoopGroup, channelClass); + BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, executor); router.onChange(changes); LiveHttpRequest request = get("/appB/hotel/details.html").build(); @@ -118,7 +113,7 @@ public void selectsApplicationBasedOnPathIfAppsAreProvidedInOppositeOrder() thro appB().newCopy().path("/appB/hotel/details.html").build(), appA().newCopy().path("/").build()); - BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, eventLoopGroup, channelClass); + BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, executor); router.onChange(changes); LiveHttpRequest request = get("/appB/hotel/details.html").build(); @@ -134,7 +129,7 @@ public void selectsUsingSingleSlashPath() throws Exception { appA().newCopy().path("/").build(), appB().newCopy().path("/appB/hotel/details.html").build()); - BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, eventLoopGroup, channelClass); + BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, executor); router.onChange(changes); LiveHttpRequest request = get("/").build(); @@ -149,7 +144,7 @@ public void selectsUsingSingleSlashPathIfAppsAreProvidedInOppositeOrder() throws appB().newCopy().path("/appB/hotel/details.html").build(), appA().newCopy().path("/").build()); - BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, eventLoopGroup, channelClass); + BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, executor); router.onChange(changes); LiveHttpRequest request = get("/").build(); @@ -164,7 +159,7 @@ public void selectsUsingPathWithNoSubsequentCharacters() throws Exception { appA().newCopy().path("/").build(), appB().newCopy().path("/appB/").build()); - BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, eventLoopGroup, channelClass); + BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, executor); router.onChange(changes); LiveHttpRequest request = get("/appB/").build(); @@ -175,7 +170,7 @@ public void selectsUsingPathWithNoSubsequentCharacters() throws Exception { @Test public void doesNotMatchRequestIfFinalSlashIsMissing() { - BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, eventLoopGroup, channelClass); + BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, executor); router.onChange(added(appB().newCopy().path("/appB/hotel/details.html").build())); LiveHttpRequest request = get("/ba/").build(); @@ -186,7 +181,7 @@ public void doesNotMatchRequestIfFinalSlashIsMissing() { @Test public void throwsExceptionWhenNoApplicationMatches() { - BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, eventLoopGroup, channelClass); + BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, executor); router.onChange(added(appB().newCopy().path("/appB/hotel/details.html").build())); LiveHttpRequest request = get("/qwertyuiop").build(); @@ -195,7 +190,7 @@ public void throwsExceptionWhenNoApplicationMatches() { @Test public void removesExistingServicesBeforeAddingNewOnes() throws Exception { - BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, eventLoopGroup, channelClass); + BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, executor); router.onChange(added(appB())); router.onChange(new Registry.Changes.Builder() @@ -210,7 +205,7 @@ public void removesExistingServicesBeforeAddingNewOnes() throws Exception { @Test public void updatesRoutesOnBackendServicesChange() throws Exception { - BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, eventLoopGroup, channelClass); + BackendServicesRouter router = new BackendServicesRouter(serviceClientFactory, environment, executor); LiveHttpRequest request = get("/appB/").build(); @@ -239,7 +234,7 @@ public void closesClientWhenBackendServicesAreUpdated() { .thenReturn(firstClient) .thenReturn(secondClient); - BackendServicesRouter router = new BackendServicesRouter(clientFactory, environment, eventLoopGroup, channelClass); + BackendServicesRouter router = new BackendServicesRouter(clientFactory, environment, executor); BackendService bookingApp = appB(); router.onChange(added(bookingApp)); @@ -267,7 +262,7 @@ public void closesClientWhenBackendServicesAreRemoved() { .thenReturn(firstClient) .thenReturn(secondClient); - BackendServicesRouter router = new BackendServicesRouter(clientFactory, environment, eventLoopGroup, channelClass); + BackendServicesRouter router = new BackendServicesRouter(clientFactory, environment, executor); BackendService bookingApp = appB(); router.onChange(added(bookingApp)); @@ -288,7 +283,7 @@ public void deregistersAndReregistersMetricsAppropriately() { .metricRegistry(metrics) .build(); BackendServicesRouter router = new BackendServicesRouter( - new StyxBackendServiceClientFactory(environment), environment, eventLoopGroup, channelClass); + new StyxBackendServiceClientFactory(environment), environment, executor); router.onChange(added(backendService(APP_B, "/appB/", 9094, "appB-01", 9095, "appB-02"))); diff --git a/components/proxy/src/test/java/com/hotels/styx/proxy/StyxProxyTest.java b/components/proxy/src/test/java/com/hotels/styx/proxy/StyxProxyTest.java index f2182cbdde..cb5a4bd8d9 100644 --- a/components/proxy/src/test/java/com/hotels/styx/proxy/StyxProxyTest.java +++ b/components/proxy/src/test/java/com/hotels/styx/proxy/StyxProxyTest.java @@ -16,6 +16,7 @@ package com.hotels.styx.proxy; import com.google.common.collect.ImmutableList; +import com.hotels.styx.NettyExecutor; import com.hotels.styx.api.Eventual; import com.hotels.styx.api.HttpInterceptor; import com.hotels.styx.api.HttpRequest; @@ -24,14 +25,11 @@ import com.hotels.styx.client.HttpClient; import com.hotels.styx.client.StyxHttpClient; import com.hotels.styx.common.http.handler.HttpAggregator; -import com.hotels.styx.infrastructure.configuration.yaml.YamlConfig; import com.hotels.styx.routing.handlers.HttpInterceptorPipeline; import com.hotels.styx.server.HttpConnectorConfig; import com.hotels.styx.server.HttpServer; import com.hotels.styx.server.StandardHttpRouter; import com.hotels.styx.server.netty.NettyServerBuilder; -import com.hotels.styx.server.netty.NettyServerBuilderSpec; -import com.hotels.styx.server.netty.NettyServerConfig; import com.hotels.styx.server.netty.ServerConnector; import com.hotels.styx.server.netty.WebServerConnectorFactory; import org.junit.jupiter.api.Disabled; @@ -43,7 +41,6 @@ import static com.hotels.styx.api.HttpResponseStatus.OK; import static com.hotels.styx.common.StyxFutures.await; -import static com.hotels.styx.common.io.ResourceFactory.newResource; import static java.nio.charset.StandardCharsets.UTF_8; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; @@ -53,21 +50,12 @@ public class StyxProxyTest extends SSLSetup { final HttpClient client = new StyxHttpClient.Builder() .build(); - public static void main(String[] args) { - NettyServerConfig config = new YamlConfig(newResource("classpath:default.yaml")) - .get("proxy", NettyServerConfig.class).get(); - - HttpServer server = new NettyServerBuilderSpec() - .toNettyServerBuilder(config) - .build(); - - server.startAsync().awaitRunning(); - } - @Test public void startsAndStopsAServer() { HttpServer server = new NettyServerBuilder() .setProtocolConnector(connector(0)) + .bossExecutor(NettyExecutor.create("Test-Server-Boss", 1)) + .workerExecutor(NettyExecutor.create("Test-Server-Worker", 0)) .build(); server.startAsync().awaitRunning(); @@ -84,6 +72,8 @@ public void startsServerWithHttpConnector() { HttpServer server = NettyServerBuilder.newBuilder() .setProtocolConnector(connector(0)) + .bossExecutor(NettyExecutor.create("Test-Server-Boss", 1)) + .workerExecutor(NettyExecutor.create("Test-Server-Worker", 0)) .handler(new HttpInterceptorPipeline( ImmutableList.of(echoInterceptor), (request, context) -> new HttpAggregator(new StandardHttpRouter()).handle(request, context), diff --git a/components/proxy/src/test/java/com/hotels/styx/routing/StaticPipelineBuilderTest.java b/components/proxy/src/test/java/com/hotels/styx/routing/StaticPipelineBuilderTest.java index c33cf5ce9e..29dbb2e378 100644 --- a/components/proxy/src/test/java/com/hotels/styx/routing/StaticPipelineBuilderTest.java +++ b/components/proxy/src/test/java/com/hotels/styx/routing/StaticPipelineBuilderTest.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,20 +17,20 @@ import com.google.common.collect.ImmutableList; import com.hotels.styx.Environment; +import com.hotels.styx.NettyExecutor; import com.hotels.styx.api.HttpHandler; import com.hotels.styx.api.LiveHttpResponse; import com.hotels.styx.api.extension.service.BackendService; import com.hotels.styx.api.extension.service.spi.AbstractRegistry; import com.hotels.styx.api.extension.service.spi.Registry; import com.hotels.styx.api.plugins.spi.Plugin; -import com.hotels.styx.client.netty.eventloop.PlatformAwareClientEventLoopGroupFactory; import com.hotels.styx.proxy.BackendServiceClientFactory; import com.hotels.styx.proxy.plugin.NamedPlugin; import com.hotels.styx.server.HttpInterceptorContext; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.socket.SocketChannel; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import reactor.core.publisher.Mono; import java.util.concurrent.CompletableFuture; @@ -46,17 +46,22 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +@TestInstance(PER_CLASS) public class StaticPipelineBuilderTest { private Environment environment; private BackendServiceClientFactory clientFactory; private Registry registry; - private final PlatformAwareClientEventLoopGroupFactory factory = new PlatformAwareClientEventLoopGroupFactory("Styx", 0); - private final EventLoopGroup eventLoopGroup = factory.newClientWorkerEventLoopGroup(); - private final Class socketChannelClass = factory.clientSocketChannelClass(); + private final NettyExecutor executor = NettyExecutor.create("Styx", 0); + + @AfterAll + public void tearDown() { + executor.shut(); + } @BeforeEach public void staticPipelineBuilderTest() { @@ -68,7 +73,7 @@ public void staticPipelineBuilderTest() { @Test public void buildsInterceptorPipelineForBackendServices() throws Exception { - HttpHandler handler = new StaticPipelineFactory(clientFactory, environment, registry, ImmutableList.of(), eventLoopGroup, socketChannelClass, false).build(); + HttpHandler handler = new StaticPipelineFactory(clientFactory, environment, registry, ImmutableList.of(), executor, false).build(); LiveHttpResponse response = Mono.from(handler.handle(get("/foo").build(), HttpInterceptorContext.create())).block(); assertThat(response.status(), is(OK)); } @@ -80,7 +85,7 @@ public void appliesPluginsInOrderTheyAreConfigured() throws Exception { interceptor("Test-B", appendResponseHeader("X-From-Plugin", "B")) ); - HttpHandler handler = new StaticPipelineFactory(clientFactory, environment, registry, plugins, eventLoopGroup, socketChannelClass, false).build(); + HttpHandler handler = new StaticPipelineFactory(clientFactory, environment, registry, plugins, executor, false).build(); LiveHttpResponse response = Mono.from(handler.handle(get("/foo").build(), HttpInterceptorContext.create())).block(); assertThat(response.status(), is(OK)); diff --git a/components/server/src/main/java/com/hotels/styx/server/HttpServers.java b/components/server/src/main/java/com/hotels/styx/server/HttpServers.java index 5ba71ae852..d733204d33 100644 --- a/components/server/src/main/java/com/hotels/styx/server/HttpServers.java +++ b/components/server/src/main/java/com/hotels/styx/server/HttpServers.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ package com.hotels.styx.server; +import com.hotels.styx.NettyExecutor; import com.hotels.styx.api.HttpHandler; import com.hotels.styx.server.netty.NettyServerBuilder; import com.hotels.styx.server.netty.WebServerConnectorFactory; @@ -31,9 +32,9 @@ public class HttpServers { */ public static HttpServer createHttpServer(int port, HttpHandler handler) { return NettyServerBuilder.newBuilder() - .name("NettyServer") .setProtocolConnector(new WebServerConnectorFactory().create(new HttpConnectorConfig(port))) .handler(handler) + .workerExecutor(NettyExecutor.create("NettyServer", 1)) .build(); } @@ -48,9 +49,9 @@ public static HttpServer createHttpServer(int port, HttpHandler handler) { */ public static HttpServer createHttpServer(String name, HttpConnectorConfig httpConnectorConfig, HttpHandler handler) { return NettyServerBuilder.newBuilder() - .name(name) .setProtocolConnector(new WebServerConnectorFactory().create(httpConnectorConfig)) .handler(handler) + .workerExecutor(NettyExecutor.create(name, 1)) .build(); } @@ -65,9 +66,9 @@ public static HttpServer createHttpServer(String name, HttpConnectorConfig httpC */ public static HttpServer createHttpsServer(String name, HttpsConnectorConfig httpsConnectorConfig, HttpHandler handler) { return NettyServerBuilder.newBuilder() - .name(name) .setProtocolConnector(new WebServerConnectorFactory().create(httpsConnectorConfig)) .handler(handler) + .workerExecutor(NettyExecutor.create(name, 1)) .build(); } diff --git a/components/server/src/main/java/com/hotels/styx/server/ServerEventLoopFactory.java b/components/server/src/main/java/com/hotels/styx/server/ServerEventLoopFactory.java deleted file mode 100644 index 2df7675989..0000000000 --- a/components/server/src/main/java/com/hotels/styx/server/ServerEventLoopFactory.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - Copyright (C) 2013-2019 Expedia Inc. - - 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 com.hotels.styx.server; - -import io.netty.channel.EventLoopGroup; -import io.netty.channel.ServerChannel; - -/** - * Factory for creating netty channel implementation based on the current system. - */ -public interface ServerEventLoopFactory { - /** - * EventLoopGroup for establishing new channels. - * - * @return event loop group - */ - EventLoopGroup newBossEventLoopGroup(); - - /** - * EventLoopGroup for handling events on channels. - * - * @return event loop group - */ - EventLoopGroup newWorkerEventLoopGroup(); - - Class serverChannelClass(); - -} diff --git a/components/server/src/main/java/com/hotels/styx/server/netty/NettyServer.java b/components/server/src/main/java/com/hotels/styx/server/netty/NettyServer.java index 320f05db86..b6e38fb6b3 100644 --- a/components/server/src/main/java/com/hotels/styx/server/netty/NettyServer.java +++ b/components/server/src/main/java/com/hotels/styx/server/netty/NettyServer.java @@ -16,18 +16,15 @@ package com.hotels.styx.server.netty; import com.google.common.util.concurrent.AbstractService; +import com.hotels.styx.NettyExecutor; import com.hotels.styx.api.HttpHandler; import com.hotels.styx.server.HttpServer; -import com.hotels.styx.server.ServerEventLoopFactory; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.PooledByteBufAllocator; import io.netty.channel.Channel; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelInitializer; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.ServerChannel; import io.netty.channel.group.ChannelGroup; -import io.netty.util.concurrent.EventExecutorGroup; import io.netty.util.concurrent.Future; import org.slf4j.Logger; @@ -54,11 +51,12 @@ final class NettyServer extends AbstractService implements HttpServer { private static final Logger LOGGER = getLogger(NettyServer.class); private final ChannelGroup channelGroup; - private final ServerEventLoopFactory serverEventLoopFactory; private final HttpHandler handler; private final ServerConnector serverConnector; private final String host; + private final NettyExecutor bossExecutor; + private final NettyExecutor workerExecutor; private volatile Callable stopper; private volatile InetSocketAddress address; @@ -66,9 +64,10 @@ final class NettyServer extends AbstractService implements HttpServer { NettyServer(NettyServerBuilder nettyServerBuilder) { this.host = nettyServerBuilder.host(); this.channelGroup = requireNonNull(nettyServerBuilder.channelGroup()); - this.serverEventLoopFactory = requireNonNull(nettyServerBuilder.serverEventLoopFactory(), "serverEventLoopFactory cannot be null"); this.handler = requireNonNull(nettyServerBuilder.handler()); this.serverConnector = nettyServerBuilder.protocolConnector(); + this.bossExecutor = nettyServerBuilder.bossExecutor(); + this.workerExecutor = nettyServerBuilder.workerExecutor(); } @Override @@ -89,12 +88,9 @@ protected void doStart() { LOGGER.info("starting services"); ServerBootstrap b = new ServerBootstrap(); - EventLoopGroup bossGroup = serverEventLoopFactory.newBossEventLoopGroup(); - EventLoopGroup workerGroup = serverEventLoopFactory.newWorkerEventLoopGroup(); - Class channelType = serverEventLoopFactory.serverChannelClass(); - b.group(bossGroup, workerGroup) - .channel(channelType) + b.group(bossExecutor.eventLoopGroup(), workerExecutor.eventLoopGroup()) + .channel(bossExecutor.serverEventLoopClass()) .option(SO_BACKLOG, 1024) .option(SO_REUSEADDR, true) .childOption(SO_REUSEADDR, true) @@ -118,7 +114,7 @@ protected void initChannel(Channel ch) throws Exception { channelGroup.add(channel); address = (InetSocketAddress) channel.localAddress(); LOGGER.info("server connector {} bound successfully on port {} socket port {}", new Object[]{serverConnector.getClass(), port, address}); - stopper = new Stopper(bossGroup, workerGroup); + stopper = new Stopper(bossExecutor, workerExecutor); notifyStarted(); } else { LOGGER.warn("Failed to start service={} cause={}", this, future.cause()); @@ -147,10 +143,10 @@ private Throwable mapToBetterException(Throwable cause, int port) { } private class Stopper implements Callable { - private final EventLoopGroup bossGroup; - private final EventLoopGroup workerGroup; + private final NettyExecutor bossGroup; + private final NettyExecutor workerGroup; - public Stopper(EventLoopGroup bossGroup, EventLoopGroup workerGroup) { + public Stopper(NettyExecutor bossGroup, NettyExecutor workerGroup) { this.bossGroup = bossGroup; this.workerGroup = workerGroup; } @@ -164,8 +160,8 @@ public Void call() { return null; } - private Future shutdownEventExecutorGroup(EventExecutorGroup eventExecutorGroup) { - return eventExecutorGroup.shutdownGracefully(10, 1000, MILLISECONDS); + private Future shutdownEventExecutorGroup(NettyExecutor eventExecutorGroup) { + return eventExecutorGroup.eventLoopGroup().shutdownGracefully(10, 1000, MILLISECONDS); } } } diff --git a/components/server/src/main/java/com/hotels/styx/server/netty/NettyServerBuilder.java b/components/server/src/main/java/com/hotels/styx/server/netty/NettyServerBuilder.java index 81ee6abfbc..516eee3fcf 100644 --- a/components/server/src/main/java/com/hotels/styx/server/netty/NettyServerBuilder.java +++ b/components/server/src/main/java/com/hotels/styx/server/netty/NettyServerBuilder.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,34 +15,33 @@ */ package com.hotels.styx.server.netty; +import com.hotels.styx.NettyExecutor; import com.hotels.styx.api.Eventual; import com.hotels.styx.api.HttpHandler; import com.hotels.styx.api.MetricRegistry; import com.hotels.styx.server.HttpServer; -import com.hotels.styx.server.ServerEventLoopFactory; -import com.hotels.styx.server.netty.eventloop.PlatformAwareServerEventLoopFactory; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.util.concurrent.ImmediateEventExecutor; import static com.google.common.base.Objects.firstNonNull; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import static com.hotels.styx.api.HttpResponseStatus.NOT_FOUND; import static com.hotels.styx.api.LiveHttpResponse.response; -import static com.hotels.styx.server.netty.eventloop.ServerEventLoopFactories.memoize; /** * A builder of {@link NettyServer} instances. */ public final class NettyServerBuilder { private final ChannelGroup channelGroup = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE); - private ServerEventLoopFactory serverEventLoopFactory; private String host; private MetricRegistry metricRegistry; - private String name = "styx"; private ServerConnector httpConnector; private HttpHandler handler = (request, context) -> Eventual.of(response(NOT_FOUND).build()); + private NettyExecutor bossExecutor; + private NettyExecutor workerExecutor; public static NettyServerBuilder newBuilder() { return new NettyServerBuilder(); @@ -57,11 +56,6 @@ public NettyServerBuilder host(String host) { return this; } - public NettyServerBuilder name(String name) { - this.name = name; - return this; - } - public NettyServerBuilder setMetricsRegistry(MetricRegistry metricRegistry) { this.metricRegistry = metricRegistry; return this; @@ -71,13 +65,22 @@ MetricRegistry metricsRegistry() { return this.metricRegistry; } - public NettyServerBuilder setServerEventLoopFactory(ServerEventLoopFactory serverEventLoopFactory) { - this.serverEventLoopFactory = serverEventLoopFactory; + public NettyServerBuilder bossExecutor(NettyExecutor executor) { + this.bossExecutor = checkNotNull(executor, "boss executor"); + return this; + } + + public NettyServerBuilder workerExecutor(NettyExecutor executor) { + this.workerExecutor = checkNotNull(executor, "worker executor"); return this; } - ServerEventLoopFactory serverEventLoopFactory() { - return firstNonNull(this.serverEventLoopFactory, memoize(new PlatformAwareServerEventLoopFactory(name, 1, 1))); + public NettyExecutor bossExecutor() { + return this.bossExecutor; + } + + public NettyExecutor workerExecutor() { + return this.workerExecutor; } public ChannelGroup channelGroup() { @@ -104,7 +107,11 @@ ServerConnector protocolConnector() { public HttpServer build() { checkArgument(httpConnector != null, "Must configure a protocol connector"); + checkArgument(workerExecutor != null, "Must configure a worker executor"); + if (bossExecutor == null) { + bossExecutor = NettyExecutor.create("Server-Boss", 1); + } return new NettyServer(this); } } diff --git a/components/server/src/main/java/com/hotels/styx/server/netty/NettyServerBuilderSpec.java b/components/server/src/main/java/com/hotels/styx/server/netty/NettyServerBuilderSpec.java deleted file mode 100644 index fd23932255..0000000000 --- a/components/server/src/main/java/com/hotels/styx/server/netty/NettyServerBuilderSpec.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - Copyright (C) 2013-2019 Expedia Inc. - - 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 com.hotels.styx.server.netty; - -import com.hotels.styx.server.ServerEnvironment; -import com.hotels.styx.server.ServerEventLoopFactory; -import com.hotels.styx.server.netty.eventloop.PlatformAwareServerEventLoopFactory; -import org.slf4j.Logger; - -import static com.hotels.styx.server.netty.eventloop.ServerEventLoopFactories.memoize; -import static java.util.Objects.requireNonNull; -import static org.slf4j.LoggerFactory.getLogger; - -/** - * A specification of a {@link NettyServerBuilder} configuration. - *

- *

{@code NettyServerBuilderSpec} supports parsing configuration off a yaml string. - */ -public class NettyServerBuilderSpec { - private static final Logger LOG = getLogger(NettyServerBuilderSpec.class); - private final String name; - private final ServerEnvironment environment; - private final ServerConnectorFactory connectorFactory; - - public NettyServerBuilderSpec(String name, ServerEnvironment environment, ServerConnectorFactory connectorFactory) { - this.name = requireNonNull(name); - this.environment = requireNonNull(environment); - this.connectorFactory = requireNonNull(connectorFactory); - } - - public NettyServerBuilderSpec() { - this("Styx", new ServerEnvironment(), new WebServerConnectorFactory()); - } - - public NettyServerBuilder toNettyServerBuilder(NettyServerConfig serverConfig) { - LOG.info("connectors={} name={}", serverConfig.connectors(), name); - - NettyServerBuilder builder = NettyServerBuilder.newBuilder() - .setMetricsRegistry(environment.metricRegistry()) - .setServerEventLoopFactory(serverEventLoopFactory(serverConfig)); - - serverConfig.httpConnectorConfig().ifPresent(httpConnector -> - builder.setProtocolConnector(connectorFactory.create(httpConnector))); - - return builder; - } - - private ServerEventLoopFactory serverEventLoopFactory(NettyServerConfig serverConfig) { - return memoize(new PlatformAwareServerEventLoopFactory(name, serverConfig.bossThreadsCount(), serverConfig.workerThreadsCount())); - } -} diff --git a/components/server/src/main/java/com/hotels/styx/server/netty/connectors/HttpPipelineHandler.java b/components/server/src/main/java/com/hotels/styx/server/netty/connectors/HttpPipelineHandler.java index 059d7dc0d5..4d348143cd 100644 --- a/components/server/src/main/java/com/hotels/styx/server/netty/connectors/HttpPipelineHandler.java +++ b/components/server/src/main/java/com/hotels/styx/server/netty/connectors/HttpPipelineHandler.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,7 +22,6 @@ import com.hotels.styx.api.ContentOverflowException; import com.hotels.styx.api.Eventual; import com.hotels.styx.api.HttpHandler; -import com.hotels.styx.api.HttpInterceptor; import com.hotels.styx.api.HttpResponseStatus; import com.hotels.styx.api.LiveHttpRequest; import com.hotels.styx.api.LiveHttpResponse; @@ -73,6 +72,7 @@ import static com.hotels.styx.api.HttpResponseStatus.REQUEST_TIMEOUT; import static com.hotels.styx.api.HttpResponseStatus.SERVICE_UNAVAILABLE; import static com.hotels.styx.api.HttpVersion.HTTP_1_1; +import static com.hotels.styx.api.LiveHttpResponse.response; import static com.hotels.styx.server.HttpErrorStatusListener.IGNORE_ERROR_STATUS; import static com.hotels.styx.server.RequestProgressListener.IGNORE_REQUEST_PROGRESS; import static com.hotels.styx.server.netty.connectors.HttpPipelineHandler.State.ACCEPTING_REQUESTS; @@ -264,7 +264,9 @@ private State onLegitimateRequest(LiveHttpRequest request, ChannelHandlerContext // the same call stack as "onLegitimateRequest" handler. This happens when a plugin // generates a response. try { - Eventual responseEventual = httpPipeline.handle(v11Request, newInterceptorContext(ctx)); + Eventual responseEventual = httpPipeline.handle( + v11Request, + new HttpInterceptorContext(this.secure, remoteAddress(ctx))); responseEventual.subscribe(new BaseSubscriber() { @Override public void hookOnSubscribe(Subscription s) { @@ -301,10 +303,6 @@ public void hookOnNext(LiveHttpResponse response) { } } - private HttpInterceptor.Context newInterceptorContext(ChannelHandlerContext ctx) { - return new HttpInterceptorContext(this.secure, remoteAddress(ctx)); - } - private State onResponseReceived(LiveHttpResponse response, ChannelHandlerContext ctx) { ongoingResponse = response; HttpResponseWriter httpResponseWriter = responseWriterFactory.create(ctx); @@ -498,7 +496,7 @@ private State onResponseObservableCompletedTooSoon(ChannelHandlerContext ctx, Ob cancelSubscription(); statsSink.onTerminate(ongoingRequest.id()); tracker.endTrack(ongoingRequest); - responseWriterFactory.create(ctx).write(LiveHttpResponse.response(INTERNAL_SERVER_ERROR).build()) + responseWriterFactory.create(ctx).write(response(INTERNAL_SERVER_ERROR).build()) .handle((dontCare, ignore) -> ctx.close()); return TERMINATED; } @@ -515,8 +513,7 @@ private LiveHttpResponse exceptionToResponse(Throwable exception, LiveHttpReques String message = status.code() >= 500 ? "Site temporarily unavailable." : status.description(); return responseEnhancer.enhance( - LiveHttpResponse - .response(status) + response(status) .body(new ByteStream(Flux.just(new Buffer(message, UTF_8)))) .build() .newBuilder(), request) diff --git a/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/PlatformAwareServerEventLoopFactory.java b/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/PlatformAwareServerEventLoopFactory.java deleted file mode 100644 index d2ccbbfe7c..0000000000 --- a/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/PlatformAwareServerEventLoopFactory.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - Copyright (C) 2013-2018 Expedia Inc. - - 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 com.hotels.styx.server.netty.eventloop; - -import com.hotels.styx.server.ServerEventLoopFactory; -import com.hotels.styx.server.netty.eventloop.epoll.EpollServerEventLoopGroupFactory; -import com.hotels.styx.server.netty.eventloop.nio.NioServerEventLoopGroupFactory; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.ServerChannel; -import io.netty.channel.epoll.Epoll; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A factory that creates platform aware server event loops. - */ -public class PlatformAwareServerEventLoopFactory implements ServerEventLoopFactory { - private static final Logger LOG = LoggerFactory.getLogger(PlatformAwareServerEventLoopFactory.class); - private final ServerEventLoopFactory delegate; - - public PlatformAwareServerEventLoopFactory(String name, int bossThreadsCount, int workerThreadsCount) { - if (Epoll.isAvailable()) { - LOG.info("Epoll is available so using the native socket transport."); - delegate = new EpollServerEventLoopGroupFactory(name, bossThreadsCount, workerThreadsCount); - } else { - LOG.info("Epoll not available Using nio socket transport."); - delegate = new NioServerEventLoopGroupFactory(name, bossThreadsCount, workerThreadsCount); - } - } - - @Override - public EventLoopGroup newBossEventLoopGroup() { - return delegate.newBossEventLoopGroup(); - } - - @Override - public EventLoopGroup newWorkerEventLoopGroup() { - return delegate.newWorkerEventLoopGroup(); - } - - @Override - public Class serverChannelClass() { - return delegate.serverChannelClass(); - } -} diff --git a/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/ServerEventLoopFactories.java b/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/ServerEventLoopFactories.java deleted file mode 100644 index eeceea4eda..0000000000 --- a/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/ServerEventLoopFactories.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - Copyright (C) 2013-2018 Expedia Inc. - - 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 com.hotels.styx.server.netty.eventloop; - -import com.hotels.styx.server.ServerEventLoopFactory; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.ServerChannel; - -import static java.util.Objects.requireNonNull; - - -/** - * Static utility methods pertaining to {@code ServerEventLoopFactory} instances. - */ -public final class ServerEventLoopFactories { - private ServerEventLoopFactories() { - } - - /** - * Returns a ServerEventLoopFactory which caches the instance retrieved during the first - * call to {@code newBossEventLoopGroup}, {@code newWorkerEventLoopGroup} and returns that value on subsequent calls. - */ - public static ServerEventLoopFactory memoize(ServerEventLoopFactory serverEventLoopFactory) { - return new MemoizingServerEventLoopFactory(requireNonNull(serverEventLoopFactory)); - } - - private static class MemoizingServerEventLoopFactory implements ServerEventLoopFactory { - private final EventLoopGroup bossEventExecutors; - private final EventLoopGroup workerEventExecutors; - private final Class serverChannelClass; - - public MemoizingServerEventLoopFactory(ServerEventLoopFactory delegate) { - this.bossEventExecutors = delegate.newBossEventLoopGroup(); - this.workerEventExecutors = delegate.newWorkerEventLoopGroup(); - this.serverChannelClass = delegate.serverChannelClass(); - } - - @Override - public EventLoopGroup newBossEventLoopGroup() { - return bossEventExecutors; - } - - @Override - public EventLoopGroup newWorkerEventLoopGroup() { - return workerEventExecutors; - } - - @Override - public Class serverChannelClass() { - return serverChannelClass; - } - } - -} diff --git a/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/epoll/EpollServerEventLoopGroupFactory.java b/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/epoll/EpollServerEventLoopGroupFactory.java deleted file mode 100644 index 8d0127458c..0000000000 --- a/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/epoll/EpollServerEventLoopGroupFactory.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - Copyright (C) 2013-2019 Expedia Inc. - - 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 com.hotels.styx.server.netty.eventloop.epoll; - -import com.hotels.styx.server.ServerEventLoopFactory; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.ServerChannel; -import io.netty.channel.epoll.EpollServerSocketChannel; - -import static com.hotels.styx.common.Preconditions.checkArgument; -import static com.hotels.styx.server.netty.eventloop.epoll.EpollEventLoopGroups.newEventLoopGroup; -import static java.util.Objects.requireNonNull; - -/** - * A factory for creating Epoll based server event loop. - */ -public class EpollServerEventLoopGroupFactory implements ServerEventLoopFactory { - private final String name; - private final int bossThreadsCount; - private final int workerThreadsCount; - - public EpollServerEventLoopGroupFactory(String name, int bossThreadsCount, int workerThreadsCount) { - this.name = requireNonNull(name); - this.bossThreadsCount = checkArgument(bossThreadsCount, bossThreadsCount > -1); - this.workerThreadsCount = checkArgument(workerThreadsCount, workerThreadsCount > -1); - } - - @Override - public EventLoopGroup newBossEventLoopGroup() { - return newEventLoopGroup(bossThreadsCount, name + "-Boss-%d-Thread"); - } - - @Override - public EventLoopGroup newWorkerEventLoopGroup() { - return newEventLoopGroup(workerThreadsCount, name + "-Worker-%d-Thread"); - } - - @Override - public Class serverChannelClass() { - return EpollServerSocketChannel.class; - } - -} diff --git a/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/nio/NioEventLoopGroups.java b/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/nio/NioEventLoopGroups.java deleted file mode 100644 index c397ee2eec..0000000000 --- a/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/nio/NioEventLoopGroups.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - Copyright (C) 2013-2018 Expedia Inc. - - 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 com.hotels.styx.server.netty.eventloop.nio; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; - -/** - * Creates NioEventLoopGroup instances. - */ -public class NioEventLoopGroups { - public static EventLoopGroup newEventLoopGroup(int threadsCount, String threadsNameFormat) { - return new NioEventLoopGroup(threadsCount, new ThreadFactoryBuilder() - .setNameFormat(threadsNameFormat) - .build()); - } -} diff --git a/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/nio/NioServerEventLoopGroupFactory.java b/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/nio/NioServerEventLoopGroupFactory.java deleted file mode 100644 index a930b07985..0000000000 --- a/components/server/src/main/java/com/hotels/styx/server/netty/eventloop/nio/NioServerEventLoopGroupFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - Copyright (C) 2013-2018 Expedia Inc. - - 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 com.hotels.styx.server.netty.eventloop.nio; - -import com.hotels.styx.server.ServerEventLoopFactory; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.ServerChannel; -import io.netty.channel.socket.nio.NioServerSocketChannel; - -import static com.hotels.styx.server.netty.eventloop.nio.NioEventLoopGroups.newEventLoopGroup; - - -/** - * A factory for creating Nio based client event loop. - * - */ -public class NioServerEventLoopGroupFactory implements ServerEventLoopFactory { - private final EventLoopGroup bossEventExecutors; - private final EventLoopGroup workerEventExecutors; - - public NioServerEventLoopGroupFactory(String name, int bossThreadsCount, int workerThreadsCount) { - this.bossEventExecutors = newEventLoopGroup(bossThreadsCount, name + "-Boss-%d-Thread"); - this.workerEventExecutors = newEventLoopGroup(workerThreadsCount, name + "-Worker-%d-Thread"); - } - - @Override - public EventLoopGroup newBossEventLoopGroup() { - return bossEventExecutors; - } - - - @Override - public EventLoopGroup newWorkerEventLoopGroup() { - return workerEventExecutors; - } - - @Override - public Class serverChannelClass() { - return NioServerSocketChannel.class; - } - -} diff --git a/system-tests/e2e-suite/src/test/resources/logback.xml b/system-tests/e2e-suite/src/test/resources/logback.xml index fe85f00ef1..f2e754c0cf 100644 --- a/system-tests/e2e-suite/src/test/resources/logback.xml +++ b/system-tests/e2e-suite/src/test/resources/logback.xml @@ -18,5 +18,6 @@ + diff --git a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/MockServer.scala b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/MockServer.scala index ce1ceef8d5..1a837119a3 100644 --- a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/MockServer.scala +++ b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/MockServer.scala @@ -24,7 +24,8 @@ import com.hotels.styx.api._ import com.hotels.styx.api.extension.Origin.newOriginBuilder import com.hotels.styx.common.http.handler.{HttpAggregator, NotFoundHandler} import com.hotels.styx.server.netty.{NettyServerBuilder, ServerConnector, WebServerConnectorFactory} -import com.hotels.styx.server.{HttpConnectorConfig, HttpServer} +import com.hotels.styx.server.HttpServer +import com.hotels.styx.support.configuration.HttpConnectorConfig class RequestRecordingHandler(val requestQueue: BlockingQueue[LiveHttpRequest], val delegate: HttpHandler) extends HttpHandler { override def handle(request: LiveHttpRequest, context: HttpInterceptor.Context): Eventual[LiveHttpResponse] = { @@ -55,8 +56,8 @@ class MockServer(id: String, val port: Int) extends AbstractIdleService with Htt } val requestQueue: BlockingQueue[LiveHttpRequest] = new LinkedBlockingQueue val server = NettyServerBuilder.newBuilder() - .name("MockServer") - .setProtocolConnector(new WebServerConnectorFactory().create(new HttpConnectorConfig(port))) + .setProtocolConnector(new WebServerConnectorFactory().create(HttpConnectorConfig(port).asJava)) + .workerExecutor(NettyExecutor.create("MockServer", 1)) .handler(router) .build() @@ -92,7 +93,7 @@ class MockServer(id: String, val port: Int) extends AbstractIdleService with Htt } private def connectorOnFreePort: ServerConnector = { - new WebServerConnectorFactory().create(new HttpConnectorConfig(0)) + new WebServerConnectorFactory().create(HttpConnectorConfig(0).asJava) } def httpPort() = Option(server.inetAddress()).map(_.getPort).getOrElse(0) diff --git a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/support/NettyOrigins.scala b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/support/NettyOrigins.scala index 9efd9b3148..7fcb63cfb5 100644 --- a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/support/NettyOrigins.scala +++ b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/support/NettyOrigins.scala @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package com.hotels.styx.support import java.util.concurrent.atomic.AtomicReference +import com.hotels.styx.NettyExecutor import com.hotels.styx.api.HttpHandler import com.hotels.styx.api.HttpHeaderNames.CONTENT_LENGTH import com.hotels.styx.api.Id._ @@ -52,8 +53,8 @@ trait NettyOrigins { def customResponseWebServer(port: Int, responseHandler: CustomResponseHandler): HttpServer = { val server: HttpServer = new NettyServerBuilder() - .name("Netty test origin") .setProtocolConnector(new NettyHttpServerConnector(port, responseHandler)) + .workerExecutor(NettyExecutor.create("Netty Test Origin", 1)) .build() server diff --git a/system-tests/e2e-testsupport/src/test/java/com/hotels/styx/servers/MockOriginServerTest.java b/system-tests/e2e-testsupport/src/test/java/com/hotels/styx/servers/MockOriginServerTest.java index 7a3b478d61..7dc805d566 100644 --- a/system-tests/e2e-testsupport/src/test/java/com/hotels/styx/servers/MockOriginServerTest.java +++ b/system-tests/e2e-testsupport/src/test/java/com/hotels/styx/servers/MockOriginServerTest.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -52,20 +52,20 @@ public class MockOriginServerTest { private StyxHttpClient tlsClient; @BeforeEach - public void setUp() throws Exception { + public void setUp() { client = new StyxHttpClient.Builder().build(); tlsClient = new StyxHttpClient.Builder().tlsSettings(new TlsSettings.Builder().build()).build(); oldHostNameVerifier = disableHostNameVerification(); } @AfterEach - public void tearDown() throws Exception { + public void tearDown() { server.stop(); setDefaultHostnameVerifier(oldHostNameVerifier); } @Test - public void configuresEndpoints() throws Exception { + public void configuresEndpoints() { server = MockOriginServer.create("", "", 0, new HttpConnectorConfig(0)) .start() .stub(WireMock.get(urlMatching("/.*")), aResponse() diff --git a/system-tests/ft-suite/src/test/kotlin/com/hotels/styx/admin/OriginsFileCompatibilitySpec.kt b/system-tests/ft-suite/src/test/kotlin/com/hotels/styx/admin/OriginsFileCompatibilitySpec.kt index 8cc6e5a591..321fd0d8c5 100644 --- a/system-tests/ft-suite/src/test/kotlin/com/hotels/styx/admin/OriginsFileCompatibilitySpec.kt +++ b/system-tests/ft-suite/src/test/kotlin/com/hotels/styx/admin/OriginsFileCompatibilitySpec.kt @@ -18,6 +18,7 @@ package com.hotels.styx.admin import com.github.tomakehurst.wiremock.client.WireMock import com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor import com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo +import com.hotels.styx.NettyExecutor import com.hotels.styx.admin.handlers.ServiceProviderHandler import com.hotels.styx.api.HttpHeaderNames.CONTENT_TYPE import com.hotels.styx.api.HttpHeaderNames.HOST @@ -68,7 +69,13 @@ class OriginsFileCompatibilitySpec : FunSpec() { connectors: http: port: 0 - + + request-logging: + inbound: + enabled: true + outbound: + enabled: true + providers: originsFileLoader: type: YamlFileConfigurationService @@ -97,7 +104,7 @@ class OriginsFileCompatibilitySpec : FunSpec() { styxServer.restart() test("It populates forwarding path from the origins yaml file") { - println("Object database: " + dumpObjectDatabase()) + LOGGER.info("Object database: " + dumpObjectDatabase()) eventually(2.seconds, AssertionError::class.java) { client.send(get("/1") @@ -785,4 +792,6 @@ class OriginsFileCompatibilitySpec : FunSpec() { } } -private val client: StyxHttpClient = StyxHttpClient.Builder().build() +private val client: StyxHttpClient = StyxHttpClient.Builder() + .executor(NettyExecutor.create("styx-client", 0)) + .build()