Search in sources :

Example 1 with EventLoopAwareNettyIoExecutor

use of io.servicetalk.transport.netty.internal.EventLoopAwareNettyIoExecutor in project servicetalk by apple.

the class CustomTransportTest method testCustomTransport.

@ParameterizedTest
@EnumSource(ServiceType.class)
void testCustomTransport(final ServiceType serviceType) throws Exception {
    // You can re-use the EventLoopGroup used by your Netty application, we create one to demonstrate its use.
    EventLoopAwareNettyIoExecutor ioExecutor = createIoExecutor("netty-el");
    // This is the Netty channel which is reading the request. See getServiceContext(Channel), depending
    // upon what control you want to give users knowing this may not be necessary.
    Channel c = new EmbeddedChannel();
    try {
        ServerTransport serverTransport = new InMemoryServerTransport(DEFAULT_ALLOCATOR, serviceType.grpcService);
        // Build the client with the custom transport and bridge to server's transport.
        Tester.TesterClient client = new Tester.ClientFactory() {

            @Override
            public TesterClient newClient(final GrpcClientCallFactory factory) {
                return super.newClient(factory);
            }
        }.newClient(new ClientTransportGrpcCallFactory(// Build the client transport, which just calls the server transport directly.
        (method, requestMessages) -> serverTransport.handle(c, "clientId", method, requestMessages), ioExecutor.eventLoopGroup()));
        // Test using the client.
        assertThat(client.test(newReq("scalar")).toFuture().get(), is(newResp("hello scalar")));
        assertThat(client.testRequestStream(newReqStream("req")).toFuture().get(), is(newResp("hello reqstream1, reqstream2, ")));
        assertThat(client.testResponseStream(newReq("respStream")).toFuture().get(), contains(newResp("hello respStream1"), newResp("hello respStream2")));
        assertThat(client.testBiDiStream(newReqStream("duplex")).toFuture().get(), contains(newResp("hello duplexstream1"), newResp("hello duplexstream2")));
    } finally {
        c.close();
        ioExecutor.closeAsync().toFuture().get();
    }
}
Also used : EventLoopAwareNettyIoExecutor(io.servicetalk.transport.netty.internal.EventLoopAwareNettyIoExecutor) DEFAULT_ALLOCATOR(io.servicetalk.buffer.netty.BufferAllocators.DEFAULT_ALLOCATOR) Publisher(io.servicetalk.concurrent.api.Publisher) NettyIoExecutors.createIoExecutor(io.servicetalk.transport.netty.internal.NettyIoExecutors.createIoExecutor) EmbeddedChannel(io.netty.channel.embedded.EmbeddedChannel) EnumSource(org.junit.jupiter.params.provider.EnumSource) TestRequest(io.servicetalk.grpc.netty.TesterProto.TestRequest) Utils.newResp(io.servicetalk.grpc.customtransport.Utils.newResp) Channel(io.netty.channel.Channel) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) GrpcBindableService(io.servicetalk.grpc.api.GrpcBindableService) Matchers.contains(org.hamcrest.Matchers.contains) GrpcClientCallFactory(io.servicetalk.grpc.api.GrpcClientCallFactory) TesterClient(io.servicetalk.grpc.netty.TesterProto.Tester.TesterClient) Matchers.is(org.hamcrest.Matchers.is) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Publisher.from(io.servicetalk.concurrent.api.Publisher.from) Tester(io.servicetalk.grpc.netty.TesterProto.Tester) Tester(io.servicetalk.grpc.netty.TesterProto.Tester) EmbeddedChannel(io.netty.channel.embedded.EmbeddedChannel) Channel(io.netty.channel.Channel) EventLoopAwareNettyIoExecutor(io.servicetalk.transport.netty.internal.EventLoopAwareNettyIoExecutor) EmbeddedChannel(io.netty.channel.embedded.EmbeddedChannel) TesterClient(io.servicetalk.grpc.netty.TesterProto.Tester.TesterClient) GrpcClientCallFactory(io.servicetalk.grpc.api.GrpcClientCallFactory) TesterClient(io.servicetalk.grpc.netty.TesterProto.Tester.TesterClient) EnumSource(org.junit.jupiter.params.provider.EnumSource) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest)

Example 2 with EventLoopAwareNettyIoExecutor

use of io.servicetalk.transport.netty.internal.EventLoopAwareNettyIoExecutor in project servicetalk by apple.

the class TcpServerBinder method bind.

/**
 * Create a {@link ServerContext} that represents a socket which is bound and listening on the
 * {@code listenAddress}.
 *
 * @param listenAddress The address to bind to.
 * @param config The {@link ReadOnlyTcpServerConfig} to use for the bind socket and newly accepted sockets.
 * @param autoRead if {@code true} auto read will be enabled for new {@link Channel}s.
 * @param executionContext The {@link ExecutionContext} to use for the bind socket.
 * @param connectionAcceptor The {@link ConnectionAcceptor} used to filter newly accepted sockets.
 * @param connectionFunction Used to create a new {@link NettyConnection} from a {@link Channel}.
 * @param connectionConsumer Used to consume the result of {@code connectionFunction} after initialization and
 * filtering is done. This can be used for protocol specific initialization and to start data flow.
 * @param <CC> The type of {@link ConnectionContext} that is created for each accepted socket.
 * @return a {@link Single} that completes with a {@link ServerContext} that represents a socket which is bound and
 * listening on the {@code listenAddress}.
 */
public static <CC extends ConnectionContext> Single<ServerContext> bind(SocketAddress listenAddress, final ReadOnlyTcpServerConfig config, final boolean autoRead, final ExecutionContext<?> executionContext, @Nullable final InfluencerConnectionAcceptor connectionAcceptor, final BiFunction<Channel, ConnectionObserver, Single<CC>> connectionFunction, final Consumer<CC> connectionConsumer) {
    requireNonNull(connectionFunction);
    requireNonNull(connectionConsumer);
    listenAddress = toNettyAddress(listenAddress);
    EventLoopAwareNettyIoExecutor nettyIoExecutor = toEventLoopAwareNettyIoExecutor(executionContext.ioExecutor());
    ServerBootstrap bs = new ServerBootstrap();
    configure(config, autoRead, bs, nettyIoExecutor.eventLoopGroup(), listenAddress.getClass());
    ChannelSet channelSet = new ChannelSet(executionContext.executionStrategy().isCloseOffloaded() ? executionContext.executor() : immediate());
    bs.handler(new ChannelInboundHandlerAdapter() {

        @Override
        public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
            // Verify that we do not leak pooled memory in the "accept" pipeline
            if (msg instanceof ReferenceCounted) {
                try {
                    throw new IllegalArgumentException("Unexpected ReferenceCounted msg in 'accept' pipeline: " + msg);
                } finally {
                    ((ReferenceCounted) msg).release();
                }
            }
            if (msg instanceof Channel) {
                final Channel channel = (Channel) msg;
                if (!channel.isActive()) {
                    channel.close();
                    LOGGER.debug("Channel ({}) is accepted, but was already inactive", msg);
                    return;
                } else if (!channelSet.addIfAbsent(channel)) {
                    LOGGER.warn("Channel ({}) not added to ChannelSet", msg);
                    return;
                }
            }
            ctx.fireChannelRead(msg);
        }
    });
    bs.childHandler(new io.netty.channel.ChannelInitializer<Channel>() {

        @Override
        protected void initChannel(Channel channel) {
            Single<CC> connectionSingle = connectionFunction.apply(channel, config.transportObserver().onNewConnection(channel.localAddress(), channel.remoteAddress()));
            if (connectionAcceptor != null) {
                connectionSingle = connectionSingle.flatMap(conn -> defer(() -> connectionAcceptor.accept(conn).concat(succeeded(conn))).subscribeOn(connectionAcceptor.requiredOffloads().isConnectOffloaded() ? executionContext.executor() : immediate()));
            }
            connectionSingle.beforeOnError(cause -> {
                // Getting the remote-address may involve volatile reads and potentially a syscall, so guard it.
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Failed to create a connection for remote address {}", channel.remoteAddress(), cause);
                }
                close(channel, cause);
            }).subscribe(connectionConsumer);
        }
    });
    ChannelFuture future = bs.bind(listenAddress);
    return new SubscribableSingle<ServerContext>() {

        @Override
        protected void handleSubscribe(Subscriber<? super ServerContext> subscriber) {
            subscriber.onSubscribe(() -> future.cancel(true));
            future.addListener((ChannelFuture f) -> {
                Channel channel = f.channel();
                Throwable cause = f.cause();
                if (cause == null) {
                    subscriber.onSuccess(NettyServerContext.wrap(channel, channelSet, connectionAcceptor, executionContext));
                } else {
                    close(channel, f.cause());
                    subscriber.onError(f.cause());
                }
            });
        }
    };
}
Also used : ChannelFuture(io.netty.channel.ChannelFuture) ChannelSet(io.servicetalk.transport.netty.internal.ChannelSet) Channel(io.netty.channel.Channel) EventLoopAwareNettyIoExecutor(io.servicetalk.transport.netty.internal.EventLoopAwareNettyIoExecutor) EventLoopAwareNettyIoExecutors.toEventLoopAwareNettyIoExecutor(io.servicetalk.transport.netty.internal.EventLoopAwareNettyIoExecutors.toEventLoopAwareNettyIoExecutor) SubscribableSingle(io.servicetalk.concurrent.api.internal.SubscribableSingle) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) ServerBootstrap(io.netty.bootstrap.ServerBootstrap) ServerContext(io.servicetalk.transport.api.ServerContext) NettyServerContext(io.servicetalk.transport.netty.internal.NettyServerContext) SubscribableSingle(io.servicetalk.concurrent.api.internal.SubscribableSingle) Single(io.servicetalk.concurrent.api.Single) ChannelInboundHandlerAdapter(io.netty.channel.ChannelInboundHandlerAdapter) ReferenceCounted(io.netty.util.ReferenceCounted)

Example 3 with EventLoopAwareNettyIoExecutor

use of io.servicetalk.transport.netty.internal.EventLoopAwareNettyIoExecutor in project servicetalk by apple.

the class IoUringTest method ioUringIsAvailableOnLinux.

@Test
@EnabledOnOs(value = { LINUX })
void ioUringIsAvailableOnLinux() throws Exception {
    EventLoopAwareNettyIoExecutor ioUringExecutor = null;
    try {
        IoUringUtils.tryIoUring(true);
        assertTrue(IoUringUtils.isAvailable());
        IOUring.ensureAvailability();
        ioUringExecutor = NettyIoExecutors.createIoExecutor(2, "io-uring");
        assertThat(ioUringExecutor.eventLoopGroup(), is(instanceOf(IOUringEventLoopGroup.class)));
        try (ServerContext serverContext = HttpServers.forAddress(localAddress(0)).ioExecutor(ioUringExecutor).listenStreamingAndAwait(new TestServiceStreaming());
            BlockingHttpClient client = HttpClients.forSingleAddress(serverHostAndPort(serverContext)).ioExecutor(ioUringExecutor).buildBlocking()) {
            HttpRequest request = client.post(SVC_ECHO).payloadBody("bonjour!", textSerializerUtf8());
            HttpResponse response = client.request(request);
            assertThat(response.status(), is(OK));
            assertThat(response.payloadBody(textSerializerUtf8()), is("bonjour!"));
        }
    } finally {
        IoUringUtils.tryIoUring(false);
        if (ioUringExecutor != null) {
            ioUringExecutor.closeAsync().toFuture().get();
            assertTrue(ioUringExecutor.eventLoopGroup().isShutdown());
        }
    }
}
Also used : HttpRequest(io.servicetalk.http.api.HttpRequest) ServerContext(io.servicetalk.transport.api.ServerContext) BlockingHttpClient(io.servicetalk.http.api.BlockingHttpClient) EventLoopAwareNettyIoExecutor(io.servicetalk.transport.netty.internal.EventLoopAwareNettyIoExecutor) HttpResponse(io.servicetalk.http.api.HttpResponse) EnabledOnOs(org.junit.jupiter.api.condition.EnabledOnOs) Test(org.junit.jupiter.api.Test)

Aggregations

EventLoopAwareNettyIoExecutor (io.servicetalk.transport.netty.internal.EventLoopAwareNettyIoExecutor)3 Channel (io.netty.channel.Channel)2 ServerContext (io.servicetalk.transport.api.ServerContext)2 ServerBootstrap (io.netty.bootstrap.ServerBootstrap)1 ChannelFuture (io.netty.channel.ChannelFuture)1 ChannelHandlerContext (io.netty.channel.ChannelHandlerContext)1 ChannelInboundHandlerAdapter (io.netty.channel.ChannelInboundHandlerAdapter)1 EmbeddedChannel (io.netty.channel.embedded.EmbeddedChannel)1 ReferenceCounted (io.netty.util.ReferenceCounted)1 DEFAULT_ALLOCATOR (io.servicetalk.buffer.netty.BufferAllocators.DEFAULT_ALLOCATOR)1 Publisher (io.servicetalk.concurrent.api.Publisher)1 Publisher.from (io.servicetalk.concurrent.api.Publisher.from)1 Single (io.servicetalk.concurrent.api.Single)1 SubscribableSingle (io.servicetalk.concurrent.api.internal.SubscribableSingle)1 GrpcBindableService (io.servicetalk.grpc.api.GrpcBindableService)1 GrpcClientCallFactory (io.servicetalk.grpc.api.GrpcClientCallFactory)1 Utils.newResp (io.servicetalk.grpc.customtransport.Utils.newResp)1 TestRequest (io.servicetalk.grpc.netty.TesterProto.TestRequest)1 Tester (io.servicetalk.grpc.netty.TesterProto.Tester)1 TesterClient (io.servicetalk.grpc.netty.TesterProto.Tester.TesterClient)1