Search in sources :

Example 1 with HttpExecutionStrategy

use of io.servicetalk.http.api.HttpExecutionStrategy in project servicetalk by apple.

the class ExecutionStrategyInContextTest method testStreaming.

@ParameterizedTest(name = "customStrategy={0}")
@ValueSource(booleans = { false, true })
void testStreaming(boolean customStrategy) throws Exception {
    StreamingHttpClient client = initClientAndServer(builder -> builder.listenStreaming((ctx, request, responseFactory) -> {
        serviceStrategyRef.set(ctx.executionContext().executionStrategy());
        return succeeded(responseFactory.ok());
    }), customStrategy).buildStreaming();
    clientAsCloseable = client;
    if (!customStrategy) {
        assert expectedClientStrategy == null;
        expectedClientStrategy = defaultStrategy();
        assert expectedServerStrategy == null;
        expectedServerStrategy = defaultStrategy();
    }
    HttpExecutionStrategy clientStrat = client.executionContext().executionStrategy();
    assertThat("Unexpected client strategy.", clientStrat, equalStrategies(expectedClientStrategy));
    client.request(client.get("/")).toFuture().get();
    assertThat("Unexpected service strategy", serviceStrategyRef.get(), equalStrategies(expectedServerStrategy));
    ReservedStreamingHttpConnection conn = client.reserveConnection(client.get("/")).toFuture().get();
    assertThat("Unexpected connection strategy (from execution context).", conn.executionContext().executionStrategy(), equalStrategies(expectedClientStrategy));
    assertThat("Unexpected connection strategy (from execution context).", conn.connectionContext().executionContext().executionStrategy(), equalStrategies(expectedClientStrategy));
}
Also used : AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) HttpExecutionStrategies.defaultStrategy(io.servicetalk.http.api.HttpExecutionStrategies.defaultStrategy) StreamingHttpClient(io.servicetalk.http.api.StreamingHttpClient) Single.succeeded(io.servicetalk.concurrent.api.Single.succeeded) HttpExecutionStrategies(io.servicetalk.http.api.HttpExecutionStrategies) HttpServerContext(io.servicetalk.http.api.HttpServerContext) HttpExecutionStrategy(io.servicetalk.http.api.HttpExecutionStrategy) HttpClient(io.servicetalk.http.api.HttpClient) AddressUtils.serverHostAndPort(io.servicetalk.transport.netty.internal.AddressUtils.serverHostAndPort) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) ReservedHttpConnection(io.servicetalk.http.api.ReservedHttpConnection) HttpServerBuilder(io.servicetalk.http.api.HttpServerBuilder) Nullable(javax.annotation.Nullable) BlockingHttpClient(io.servicetalk.http.api.BlockingHttpClient) ReservedBlockingStreamingHttpConnection(io.servicetalk.http.api.ReservedBlockingStreamingHttpConnection) ValueSource(org.junit.jupiter.params.provider.ValueSource) Description(org.hamcrest.Description) AddressUtils.localAddress(io.servicetalk.transport.netty.internal.AddressUtils.localAddress) ServerContext(io.servicetalk.transport.api.ServerContext) Single(io.servicetalk.concurrent.api.Single) HttpClients.forSingleAddress(io.servicetalk.http.netty.HttpClients.forSingleAddress) ReservedBlockingHttpConnection(io.servicetalk.http.api.ReservedBlockingHttpConnection) TypeSafeMatcher(org.hamcrest.TypeSafeMatcher) InetSocketAddress(java.net.InetSocketAddress) BlockingStreamingHttpClient(io.servicetalk.http.api.BlockingStreamingHttpClient) SingleAddressHttpClientBuilder(io.servicetalk.http.api.SingleAddressHttpClientBuilder) Objects(java.util.Objects) HttpExecutionStrategies.customStrategyBuilder(io.servicetalk.http.api.HttpExecutionStrategies.customStrategyBuilder) AfterEach(org.junit.jupiter.api.AfterEach) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) Matcher(org.hamcrest.Matcher) ReservedStreamingHttpConnection(io.servicetalk.http.api.ReservedStreamingHttpConnection) HostAndPort(io.servicetalk.transport.api.HostAndPort) ReservedStreamingHttpConnection(io.servicetalk.http.api.ReservedStreamingHttpConnection) StreamingHttpClient(io.servicetalk.http.api.StreamingHttpClient) BlockingStreamingHttpClient(io.servicetalk.http.api.BlockingStreamingHttpClient) HttpExecutionStrategy(io.servicetalk.http.api.HttpExecutionStrategy) ValueSource(org.junit.jupiter.params.provider.ValueSource) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest)

Example 2 with HttpExecutionStrategy

use of io.servicetalk.http.api.HttpExecutionStrategy in project servicetalk by apple.

the class NettyHttpServerConnectionTest method updateFlushStrategy.

@ParameterizedTest(name = "server={0} client={1}")
@MethodSource("executionStrategies")
void updateFlushStrategy(HttpExecutionStrategy serverExecutionStrategy, HttpExecutionStrategy clientExecutionStrategy) throws Exception {
    customStrategy = new MockFlushStrategy();
    AtomicReference<Cancellable> customCancellableRef = new AtomicReference<>();
    AtomicBoolean handledFirstRequest = new AtomicBoolean();
    serverContext = HttpServers.forAddress(localAddress(0)).ioExecutor(contextRule.ioExecutor()).appendConnectionAcceptorFilter(original -> original.append(ctx -> {
        customCancellableRef.set(((NettyConnectionContext) ctx).updateFlushStrategy((__, ___) -> customStrategy));
        return completed();
    })).executionStrategy(serverExecutionStrategy).listenStreaming((ctx, request, responseFactory) -> {
        if (handledFirstRequest.compareAndSet(false, true)) {
            customStrategy.afterFirstWrite(FlushStrategy.FlushSender::flush);
            return succeeded(responseFactory.ok().payloadBody(responsePublisher));
        }
        return succeeded(responseFactory.ok().payloadBody(responsePublisher2));
    }).toFuture().get();
    client = HttpClients.forSingleAddress(serverHostAndPort(serverContext)).executionStrategy(clientExecutionStrategy).buildStreaming();
    StreamingHttpResponse response = client.request(client.newRequest(GET, "/1")).toFuture().get();
    FlushStrategy.FlushSender customFlushSender = customStrategy.verifyApplied();
    Cancellable customCancellable = customCancellableRef.get();
    assertNotNull(customCancellable);
    // Verify that the custom strategy is applied and used for flushing.
    customStrategy.verifyWriteStarted();
    customStrategy.verifyItemWritten(1);
    customStrategy.verifyNoMoreInteractions();
    String payloadBodyString = "foo";
    TestSubscription testSubscription1 = new TestSubscription();
    responsePublisher.onSubscribe(testSubscription1);
    testSubscription1.awaitRequestN(1);
    responsePublisher.onNext(DEFAULT_ALLOCATOR.fromAscii(payloadBodyString));
    responsePublisher.onComplete();
    customFlushSender.flush();
    Buffer responsePayload = response.payloadBody().collect(DEFAULT_ALLOCATOR::newBuffer, (results, current) -> {
        results.writeBytes(current);
        return results;
    }).toFuture().get();
    assertEquals(payloadBodyString, responsePayload.toString(US_ASCII));
    customStrategy.verifyItemWritten(2);
    customStrategy.verifyWriteTerminated();
    // Restore the default flush strategy, which should flush on each
    customCancellable.cancel();
    StreamingHttpResponse response2 = client.request(client.newRequest(GET, "/2")).toFuture().get();
    TestSubscription testSubscription2 = new TestSubscription();
    responsePublisher2.onSubscribe(testSubscription2);
    responsePublisher2.onNext(DEFAULT_ALLOCATOR.fromAscii(payloadBodyString));
    responsePublisher2.onComplete();
    responsePayload = response2.payloadBody().collect(DEFAULT_ALLOCATOR::newBuffer, (results, current) -> {
        results.writeBytes(current);
        return results;
    }).toFuture().get();
    assertEquals(payloadBodyString, responsePayload.toString(US_ASCII));
}
Also used : FlushStrategy(io.servicetalk.transport.netty.internal.FlushStrategy) Assertions.assertNotNull(org.junit.jupiter.api.Assertions.assertNotNull) StreamingHttpResponse(io.servicetalk.http.api.StreamingHttpResponse) DEFAULT_ALLOCATOR(io.servicetalk.buffer.netty.BufferAllocators.DEFAULT_ALLOCATOR) TestPublisher(io.servicetalk.concurrent.api.TestPublisher) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Cancellable(io.servicetalk.concurrent.Cancellable) AtomicReference(java.util.concurrent.atomic.AtomicReference) HttpExecutionStrategies.defaultStrategy(io.servicetalk.http.api.HttpExecutionStrategies.defaultStrategy) StreamingHttpClient(io.servicetalk.http.api.StreamingHttpClient) RegisterExtension(org.junit.jupiter.api.extension.RegisterExtension) Single.succeeded(io.servicetalk.concurrent.api.Single.succeeded) HttpExecutionStrategy(io.servicetalk.http.api.HttpExecutionStrategy) AddressUtils.serverHostAndPort(io.servicetalk.transport.netty.internal.AddressUtils.serverHostAndPort) NettyConnectionContext(io.servicetalk.transport.netty.internal.NettyConnectionContext) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) MethodSource(org.junit.jupiter.params.provider.MethodSource) AddressUtils.localAddress(io.servicetalk.transport.netty.internal.AddressUtils.localAddress) ExecutionContextExtension.immediate(io.servicetalk.transport.netty.internal.ExecutionContextExtension.immediate) ServerContext(io.servicetalk.transport.api.ServerContext) ExecutionContextExtension(io.servicetalk.transport.netty.internal.ExecutionContextExtension) AsyncCloseables.newCompositeCloseable(io.servicetalk.concurrent.api.AsyncCloseables.newCompositeCloseable) Arguments(org.junit.jupiter.params.provider.Arguments) TestSubscription(io.servicetalk.concurrent.api.TestSubscription) GET(io.servicetalk.http.api.HttpRequestMethod.GET) US_ASCII(java.nio.charset.StandardCharsets.US_ASCII) AfterEach(org.junit.jupiter.api.AfterEach) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) Buffer(io.servicetalk.buffer.api.Buffer) Stream(java.util.stream.Stream) Completable.completed(io.servicetalk.concurrent.api.Completable.completed) MockFlushStrategy(io.servicetalk.transport.netty.internal.MockFlushStrategy) HttpExecutionStrategies.offloadNever(io.servicetalk.http.api.HttpExecutionStrategies.offloadNever) TestSubscription(io.servicetalk.concurrent.api.TestSubscription) Buffer(io.servicetalk.buffer.api.Buffer) Cancellable(io.servicetalk.concurrent.Cancellable) MockFlushStrategy(io.servicetalk.transport.netty.internal.MockFlushStrategy) AtomicReference(java.util.concurrent.atomic.AtomicReference) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) DEFAULT_ALLOCATOR(io.servicetalk.buffer.netty.BufferAllocators.DEFAULT_ALLOCATOR) FlushStrategy(io.servicetalk.transport.netty.internal.FlushStrategy) MockFlushStrategy(io.servicetalk.transport.netty.internal.MockFlushStrategy) StreamingHttpResponse(io.servicetalk.http.api.StreamingHttpResponse) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MethodSource(org.junit.jupiter.params.provider.MethodSource)

Example 3 with HttpExecutionStrategy

use of io.servicetalk.http.api.HttpExecutionStrategy in project servicetalk by apple.

the class InOrderRouter method handle.

@Override
public Single<StreamingHttpResponse> handle(final HttpServiceContext ctx, final StreamingHttpRequest request, final StreamingHttpResponseFactory factory) {
    for (final Route pair : routes) {
        if (pair.predicate().test(ctx, request)) {
            StreamingHttpService service = pair.service();
            final HttpExecutionStrategy strategy = pair.routeStrategy();
            HttpExecutionContext useContext = ctx.executionContext();
            if (null != strategy && useContext.executionStrategy().missing(strategy).hasOffloads()) {
                // Additional offloading needed
                service = StreamingHttpServiceToOffloadedStreamingHttpService.offloadService(strategy, useContext.executor(), IoThreadFactory.IoThread::currentThreadIsIoThread, service);
            }
            return service.handle(ctx, request, factory);
        }
    }
    return fallbackService.handle(ctx, request, factory);
}
Also used : HttpExecutionContext(io.servicetalk.http.api.HttpExecutionContext) IoThreadFactory(io.servicetalk.transport.api.IoThreadFactory) StreamingHttpServiceToOffloadedStreamingHttpService(io.servicetalk.http.api.StreamingHttpServiceToOffloadedStreamingHttpService) StreamingHttpService(io.servicetalk.http.api.StreamingHttpService) HttpExecutionStrategy(io.servicetalk.http.api.HttpExecutionStrategy)

Example 4 with HttpExecutionStrategy

use of io.servicetalk.http.api.HttpExecutionStrategy in project servicetalk by apple.

the class DefaultMultiAddressUrlHttpClientBuilder method buildStreaming.

@Override
public StreamingHttpClient buildStreaming() {
    final CompositeCloseable closeables = newCompositeCloseable();
    try {
        final HttpClientBuildContext<HostAndPort, InetSocketAddress> buildContext = builderTemplate.copyBuildCtx();
        final ClientFactory clientFactory = new ClientFactory(buildContext.builder, singleAddressInitializer);
        HttpExecutionContext executionContext = buildContext.builder.executionContextBuilder.build();
        final CachingKeyFactory keyFactory = closeables.prepend(new CachingKeyFactory());
        FilterableStreamingHttpClient urlClient = closeables.prepend(new StreamingUrlHttpClient(executionContext, clientFactory, keyFactory, defaultReqRespFactory(buildContext.httpConfig().asReadOnly(), executionContext.bufferAllocator())));
        // Need to wrap the top level client (group) in order for non-relative redirects to work
        urlClient = redirectConfig == null ? urlClient : new RedirectingHttpRequesterFilter(redirectConfig).create(urlClient);
        HttpExecutionStrategy computedStrategy = buildContext.builder.computeChainStrategy(executionContext.executionStrategy());
        LOGGER.debug("Client created with base strategy {} → computed strategy {}", executionContext.executionStrategy(), computedStrategy);
        return new FilterableClientToClient(urlClient, computedStrategy);
    } catch (final Throwable t) {
        closeables.closeAsync().subscribe();
        throw t;
    }
}
Also used : InetSocketAddress(java.net.InetSocketAddress) CompositeCloseable(io.servicetalk.concurrent.api.CompositeCloseable) AsyncCloseables.newCompositeCloseable(io.servicetalk.concurrent.api.AsyncCloseables.newCompositeCloseable) HostAndPort(io.servicetalk.transport.api.HostAndPort) HttpExecutionContext(io.servicetalk.http.api.HttpExecutionContext) FilterableStreamingHttpClient(io.servicetalk.http.api.FilterableStreamingHttpClient) HttpExecutionStrategy(io.servicetalk.http.api.HttpExecutionStrategy) RedirectingHttpRequesterFilter(io.servicetalk.http.utils.RedirectingHttpRequesterFilter)

Example 5 with HttpExecutionStrategy

use of io.servicetalk.http.api.HttpExecutionStrategy in project servicetalk by apple.

the class AbstractStreamingHttpConnection method request.

@Override
public Single<StreamingHttpResponse> request(final StreamingHttpRequest request) {
    return defer(() -> {
        Publisher<Object> flatRequest;
        // See https://tools.ietf.org/html/rfc7230#section-3.3.3
        if (canAddRequestContentLength(request)) {
            flatRequest = setRequestContentLength(connectionContext().protocol(), request);
        } else {
            if (emptyMessageBody(request, request.messageBody())) {
                flatRequest = flatEmptyMessage(connectionContext().protocol(), request, request.messageBody());
            } else {
                // Defer subscribe to the messageBody until transport requests it to allow clients retry failed
                // requests with non-replayable messageBody
                flatRequest = Single.<Object>succeeded(request).concat(request.messageBody(), true);
                if (shouldAppendTrailers(connectionContext().protocol(), request)) {
                    flatRequest = flatRequest.scanWith(HeaderUtils::appendTrailersMapper);
                }
            }
            addRequestTransferEncodingIfNecessary(request);
        }
        final HttpExecutionStrategy strategy = requestExecutionStrategy(request, executionContext().executionStrategy());
        if (strategy.isSendOffloaded()) {
            flatRequest = flatRequest.subscribeOn(connectionContext.executionContext().executor(), IoThreadFactory.IoThread::currentThreadIsIoThread);
        }
        Single<StreamingHttpResponse> resp = invokeClient(flatRequest, determineFlushStrategyForApi(request));
        if (strategy.isMetadataReceiveOffloaded()) {
            resp = resp.publishOn(connectionContext.executionContext().executor(), IoThreadFactory.IoThread::currentThreadIsIoThread);
        }
        if (strategy.isDataReceiveOffloaded()) {
            resp = resp.map(response -> response.transformMessageBody(payload -> payload.publishOn(connectionContext.executionContext().executor(), IoThreadFactory.IoThread::currentThreadIsIoThread)));
        }
        return resp.shareContextOnSubscribe();
    });
}
Also used : FlushStrategy(io.servicetalk.transport.netty.internal.FlushStrategy) HeaderUtils.canAddRequestContentLength(io.servicetalk.http.netty.HeaderUtils.canAddRequestContentLength) StreamingHttpResponse(io.servicetalk.http.api.StreamingHttpResponse) HttpRequestMethod(io.servicetalk.http.api.HttpRequestMethod) Publisher(io.servicetalk.concurrent.api.Publisher) StreamingHttpResponses.newTransportResponse(io.servicetalk.http.api.StreamingHttpResponses.newTransportResponse) ConsumableEvent(io.servicetalk.client.api.ConsumableEvent) HttpResponseMetaData(io.servicetalk.http.api.HttpResponseMetaData) HttpApiConversions.isSafeToAggregate(io.servicetalk.http.api.HttpApiConversions.isSafeToAggregate) FilterableStreamingHttpConnection(io.servicetalk.http.api.FilterableStreamingHttpConnection) FlushStrategies.flushOnEnd(io.servicetalk.transport.netty.internal.FlushStrategies.flushOnEnd) HttpMetaData(io.servicetalk.http.api.HttpMetaData) IoThreadFactory(io.servicetalk.transport.api.IoThreadFactory) Single.succeeded(io.servicetalk.concurrent.api.Single.succeeded) HttpApiConversions.isPayloadEmpty(io.servicetalk.http.api.HttpApiConversions.isPayloadEmpty) Objects.requireNonNull(java.util.Objects.requireNonNull) HttpExecutionStrategy(io.servicetalk.http.api.HttpExecutionStrategy) StreamingHttpRequest(io.servicetalk.http.api.StreamingHttpRequest) NettyConnectionContext(io.servicetalk.transport.netty.internal.NettyConnectionContext) HeaderUtils.addRequestTransferEncodingIfNecessary(io.servicetalk.http.netty.HeaderUtils.addRequestTransferEncodingIfNecessary) Publisher.from(io.servicetalk.concurrent.api.Publisher.from) ClientInvoker(io.servicetalk.http.api.ClientInvoker) HttpConnectionContext(io.servicetalk.http.api.HttpConnectionContext) Nullable(javax.annotation.Nullable) HttpExecutionContext(io.servicetalk.http.api.HttpExecutionContext) HeaderUtils.flatEmptyMessage(io.servicetalk.http.netty.HeaderUtils.flatEmptyMessage) Executors.immediate(io.servicetalk.concurrent.api.Executors.immediate) StreamingHttpRequestResponseFactory(io.servicetalk.http.api.StreamingHttpRequestResponseFactory) Single.defer(io.servicetalk.concurrent.api.Single.defer) HeaderUtils.setRequestContentLength(io.servicetalk.http.netty.HeaderUtils.setRequestContentLength) Single(io.servicetalk.concurrent.api.Single) HeaderUtils.emptyMessageBody(io.servicetalk.http.netty.HeaderUtils.emptyMessageBody) HeaderUtils.shouldAppendTrailers(io.servicetalk.http.netty.HeaderUtils.shouldAppendTrailers) Completable(io.servicetalk.concurrent.api.Completable) HTTP_EXECUTION_STRATEGY_KEY(io.servicetalk.http.api.HttpContextKeys.HTTP_EXECUTION_STRATEGY_KEY) HttpEventKey(io.servicetalk.http.api.HttpEventKey) HttpRequestMetaData(io.servicetalk.http.api.HttpRequestMetaData) IgnoreConsumedEvent(io.servicetalk.client.api.internal.IgnoreConsumedEvent) Publisher.failed(io.servicetalk.concurrent.api.Publisher.failed) StreamingHttpResponseFactory(io.servicetalk.http.api.StreamingHttpResponseFactory) REQ_EXPECT_CONTINUE(io.servicetalk.http.netty.HeaderUtils.REQ_EXPECT_CONTINUE) HttpHeadersFactory(io.servicetalk.http.api.HttpHeadersFactory) IoThreadFactory(io.servicetalk.transport.api.IoThreadFactory) HttpExecutionStrategy(io.servicetalk.http.api.HttpExecutionStrategy) StreamingHttpResponse(io.servicetalk.http.api.StreamingHttpResponse)

Aggregations

HttpExecutionStrategy (io.servicetalk.http.api.HttpExecutionStrategy)23 Single.succeeded (io.servicetalk.concurrent.api.Single.succeeded)9 StreamingHttpClient (io.servicetalk.http.api.StreamingHttpClient)9 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)9 Nullable (javax.annotation.Nullable)8 Single (io.servicetalk.concurrent.api.Single)7 HttpExecutionStrategies.defaultStrategy (io.servicetalk.http.api.HttpExecutionStrategies.defaultStrategy)7 HostAndPort (io.servicetalk.transport.api.HostAndPort)7 ServerContext (io.servicetalk.transport.api.ServerContext)7 AddressUtils.localAddress (io.servicetalk.transport.netty.internal.AddressUtils.localAddress)7 AddressUtils.serverHostAndPort (io.servicetalk.transport.netty.internal.AddressUtils.serverHostAndPort)7 InetSocketAddress (java.net.InetSocketAddress)7 AtomicReference (java.util.concurrent.atomic.AtomicReference)7 HttpExecutionContext (io.servicetalk.http.api.HttpExecutionContext)6 StreamingHttpResponse (io.servicetalk.http.api.StreamingHttpResponse)6 MatcherAssert.assertThat (org.hamcrest.MatcherAssert.assertThat)6 AfterEach (org.junit.jupiter.api.AfterEach)6 HttpExecutionStrategies (io.servicetalk.http.api.HttpExecutionStrategies)5 ReservedStreamingHttpConnection (io.servicetalk.http.api.ReservedStreamingHttpConnection)5 ValueSource (org.junit.jupiter.params.provider.ValueSource)5