Search in sources :

Example 1 with Subscriber

use of io.servicetalk.concurrent.SingleSource.Subscriber in project servicetalk by apple.

the class ServiceTalkThreadContextMapTest method testAsyncExecution.

@Test
void testAsyncExecution() throws Exception {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    try {
        MDC.clear();
        MDC.put("a", "1");
        MDC.put("b", "2");
        // human inspection as sanity check
        logger.info("expected a=1 b=2");
        Thread original = Thread.currentThread();
        Single<String> single = new Single<String>() {

            @Override
            protected void handleSubscribe(Subscriber<? super String> singleSubscriber) {
                executor.execute(() -> {
                    singleSubscriber.onSubscribe(IGNORE_CANCEL);
                    singleSubscriber.onSuccess("1");
                });
            }
        }.map(v -> {
            assertNotEquals(Thread.currentThread(), original);
            assertEquals("1", MDC.get("a"));
            assertEquals("2", MDC.get("b"));
            MDC.put("b", "22");
            return v;
        }).beforeFinally(() -> {
            // human inspection as sanity check
            logger.info("expected a=1 b=22");
            assertEquals("1", MDC.get("a"));
            assertEquals("22", MDC.get("b"));
        });
        single.toFuture().get();
    } finally {
        executor.shutdown();
    }
}
Also used : ThreadContext(org.apache.logging.log4j.ThreadContext) Assertions.fail(org.junit.jupiter.api.Assertions.fail) BeforeEach(org.junit.jupiter.api.BeforeEach) Assertions.assertNotNull(org.junit.jupiter.api.Assertions.assertNotNull) Logger(org.slf4j.Logger) Subscriber(io.servicetalk.concurrent.SingleSource.Subscriber) Single(io.servicetalk.concurrent.api.Single) LoggerFactory(org.slf4j.LoggerFactory) Assertions.assertNotEquals(org.junit.jupiter.api.Assertions.assertNotEquals) Assertions.assertNull(org.junit.jupiter.api.Assertions.assertNull) Executors(java.util.concurrent.Executors) Test(org.junit.jupiter.api.Test) ServiceTalkThreadContextMap.getStorage(io.servicetalk.log4j2.mdc.utils.ServiceTalkThreadContextMap.getStorage) IGNORE_CANCEL(io.servicetalk.concurrent.Cancellable.IGNORE_CANCEL) MDC(org.slf4j.MDC) Map(java.util.Map) Assumptions.assumeTrue(org.junit.jupiter.api.Assumptions.assumeTrue) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) Collections(java.util.Collections) ExecutorService(java.util.concurrent.ExecutorService) Single(io.servicetalk.concurrent.api.Single) Subscriber(io.servicetalk.concurrent.SingleSource.Subscriber) ExecutorService(java.util.concurrent.ExecutorService) Test(org.junit.jupiter.api.Test)

Example 2 with Subscriber

use of io.servicetalk.concurrent.SingleSource.Subscriber in project servicetalk by apple.

the class SingleProcessorTest method multiThreadedAddAlwaysTerminates.

private static void multiThreadedAddAlwaysTerminates(@Nullable String value, @Nullable Throwable cause) throws Exception {
    final int subscriberCount = 1000;
    CyclicBarrier barrier = new CyclicBarrier(subscriberCount + 1);
    List<Single<Subscriber<String>>> subscriberSingles = new ArrayList<>(subscriberCount);
    SingleProcessor<String> processor = new SingleProcessor<>();
    for (int i = 0; i < subscriberCount; ++i) {
        subscriberSingles.add(EXECUTOR_RULE.executor().submit(() -> {
            @SuppressWarnings("unchecked") Subscriber<String> subscriber = mock(Subscriber.class);
            barrier.await();
            processor.subscribe(subscriber);
            return subscriber;
        }));
    }
    Future<Collection<Subscriber<String>>> future = collectUnordered(subscriberSingles, subscriberCount).toFuture();
    barrier.await();
    if (cause != null) {
        processor.onError(cause);
        Collection<Subscriber<String>> subscribers = future.get();
        for (Subscriber<String> s : subscribers) {
            verify(s).onError(cause);
        }
    } else {
        processor.onSuccess(value);
        Collection<Subscriber<String>> subscribers = future.get();
        for (Subscriber<String> s : subscribers) {
            verify(s).onSuccess(value);
        }
    }
}
Also used : ArrayList(java.util.ArrayList) CyclicBarrier(java.util.concurrent.CyclicBarrier) Subscriber(io.servicetalk.concurrent.SingleSource.Subscriber) TestSingleSubscriber(io.servicetalk.concurrent.test.internal.TestSingleSubscriber) Collection(java.util.Collection)

Example 3 with Subscriber

use of io.servicetalk.concurrent.SingleSource.Subscriber in project servicetalk by apple.

the class BlockingStreamingToStreamingService method handle.

@Override
public Single<StreamingHttpResponse> handle(final HttpServiceContext ctx, final StreamingHttpRequest request, final StreamingHttpResponseFactory responseFactory) {
    return new Single<StreamingHttpResponse>() {

        @Override
        protected void handleSubscribe(final Subscriber<? super StreamingHttpResponse> subscriber) {
            final ThreadInterruptingCancellable tiCancellable = new ThreadInterruptingCancellable(currentThread());
            try {
                subscriber.onSubscribe(tiCancellable);
            } catch (Throwable cause) {
                handleExceptionFromOnSubscribe(subscriber, cause);
                return;
            }
            // This exists to help users with error propagation. If the user closes the payloadWriter and they throw
            // (e.g. try-with-resources) this processor is merged with the payloadWriter Publisher so the error will
            // still be propagated.
            final Processor exceptionProcessor = newCompletableProcessor();
            final BufferHttpPayloadWriter payloadWriter = new BufferHttpPayloadWriter(ctx.headersFactory().newTrailers());
            DefaultBlockingStreamingHttpServerResponse response = null;
            try {
                final Consumer<DefaultHttpResponseMetaData> sendMeta = (metaData) -> {
                    final DefaultStreamingHttpResponse result;
                    try {
                        // transfer-encoding takes precedence over content-length.
                        // > When a message does not have a Transfer-Encoding header field, a
                        // Content-Length header field can provide the anticipated size.
                        // https://tools.ietf.org/html/rfc7230#section-3.3.2
                        final HttpHeaders headers = metaData.headers();
                        final HttpProtocolVersion version = metaData.version();
                        boolean addTrailers = version.major() > 1 || isTransferEncodingChunked(headers);
                        if (!addTrailers && h1TrailersSupported(version) && !hasContentLength(headers) && // breaks our HttpResponseDecoder
                        !HEAD.equals(request.method())) {
                            // this is likely not supported in http/1.0 and it is possible that a response has
                            // neither header and the connection close indicates the end of the response.
                            // https://tools.ietf.org/html/rfc7230#section-3.3.3
                            headers.add(TRANSFER_ENCODING, CHUNKED);
                            addTrailers = true;
                        }
                        Publisher<Object> messageBody = fromSource(exceptionProcessor).merge(payloadWriter.connect());
                        if (addTrailers) {
                            messageBody = messageBody.concat(succeeded(payloadWriter.trailers()));
                        }
                        messageBody = messageBody.beforeSubscription(() -> new Subscription() {

                            @Override
                            public void request(final long n) {
                            }

                            @Override
                            public void cancel() {
                                tiCancellable.cancel();
                            }
                        });
                        result = new DefaultStreamingHttpResponse(metaData.status(), version, headers, metaData.context0(), ctx.executionContext().bufferAllocator(), messageBody, forTransportReceive(false, version, headers), ctx.headersFactory());
                    } catch (Throwable t) {
                        subscriber.onError(t);
                        throw t;
                    }
                    subscriber.onSuccess(result);
                };
                response = new DefaultBlockingStreamingHttpServerResponse(OK, request.version(), ctx.headersFactory().newHeaders(), payloadWriter, ctx.executionContext().bufferAllocator(), sendMeta);
                original.handle(ctx, request.toBlockingStreamingRequest(), response);
                // The user code has returned successfully, complete the processor so the response stream can
                // complete. If the user handles the request asynchronously (e.g. on another thread) they are
                // responsible for closing the payloadWriter.
                exceptionProcessor.onComplete();
            } catch (Throwable cause) {
                tiCancellable.setDone(cause);
                if (response == null || response.markMetaSent()) {
                    safeOnError(subscriber, cause);
                } else {
                    try {
                        exceptionProcessor.onError(cause);
                    } finally {
                        safeClose(payloadWriter, cause);
                    }
                }
                return;
            }
            tiCancellable.setDone();
        }
    };
}
Also used : HttpProtocolVersion.h1TrailersSupported(io.servicetalk.http.api.HttpProtocolVersion.h1TrailersSupported) DefaultPayloadInfo.forTransportReceive(io.servicetalk.http.api.DefaultPayloadInfo.forTransportReceive) Publisher(io.servicetalk.concurrent.api.Publisher) Subscriber(io.servicetalk.concurrent.SingleSource.Subscriber) ConnectablePayloadWriter(io.servicetalk.concurrent.api.internal.ConnectablePayloadWriter) PayloadWriterUtils.safeClose(io.servicetalk.oio.api.internal.PayloadWriterUtils.safeClose) Thread.currentThread(java.lang.Thread.currentThread) ThreadInterruptingCancellable(io.servicetalk.concurrent.internal.ThreadInterruptingCancellable) SourceAdapters.fromSource(io.servicetalk.concurrent.api.SourceAdapters.fromSource) HeaderUtils.isTransferEncodingChunked(io.servicetalk.http.api.HeaderUtils.isTransferEncodingChunked) HttpExecutionStrategies.defaultStrategy(io.servicetalk.http.api.HttpExecutionStrategies.defaultStrategy) HEAD(io.servicetalk.http.api.HttpRequestMethod.HEAD) Objects.requireNonNull(java.util.Objects.requireNonNull) SubscriberUtils.safeOnError(io.servicetalk.concurrent.internal.SubscriberUtils.safeOnError) Processors.newCompletableProcessor(io.servicetalk.concurrent.api.Processors.newCompletableProcessor) CHUNKED(io.servicetalk.http.api.HttpHeaderValues.CHUNKED) SubscriberUtils.handleExceptionFromOnSubscribe(io.servicetalk.concurrent.internal.SubscriberUtils.handleExceptionFromOnSubscribe) Single(io.servicetalk.concurrent.api.Single) Completable(io.servicetalk.concurrent.api.Completable) OFFLOAD_RECEIVE_META_STRATEGY(io.servicetalk.http.api.DefaultHttpExecutionStrategy.OFFLOAD_RECEIVE_META_STRATEGY) TRANSFER_ENCODING(io.servicetalk.http.api.HttpHeaderNames.TRANSFER_ENCODING) IOException(java.io.IOException) Subscription(io.servicetalk.concurrent.PublisherSource.Subscription) OK(io.servicetalk.http.api.HttpResponseStatus.OK) Consumer(java.util.function.Consumer) BlockingUtils.blockingToCompletable(io.servicetalk.http.api.BlockingUtils.blockingToCompletable) HeaderUtils.hasContentLength(io.servicetalk.http.api.HeaderUtils.hasContentLength) Buffer(io.servicetalk.buffer.api.Buffer) Processor(io.servicetalk.concurrent.CompletableSource.Processor) Processors.newCompletableProcessor(io.servicetalk.concurrent.api.Processors.newCompletableProcessor) Processor(io.servicetalk.concurrent.CompletableSource.Processor) ThreadInterruptingCancellable(io.servicetalk.concurrent.internal.ThreadInterruptingCancellable) Publisher(io.servicetalk.concurrent.api.Publisher) Single(io.servicetalk.concurrent.api.Single) Subscriber(io.servicetalk.concurrent.SingleSource.Subscriber) Subscription(io.servicetalk.concurrent.PublisherSource.Subscription)

Example 4 with Subscriber

use of io.servicetalk.concurrent.SingleSource.Subscriber in project servicetalk by apple.

the class ResponseTimeoutTest method setUp.

private void setUp(Duration clientTimeout, Duration serverTimeout) throws Exception {
    ctx = forAddress(localAddress(0)).appendServiceFilter(new TimeoutHttpServiceFilter((req, ts) -> serverTimeout, true)).listenAndAwait((__, ___, factory) -> {
        Single<HttpResponse> resp = Single.never();
        serverResponses.add(resp);
        return resp;
    });
    client = forSingleAddress(serverHostAndPort(ctx)).appendClientFilter(client -> new StreamingHttpClientFilter(client) {

        @Override
        protected Single<StreamingHttpResponse> request(final StreamingHttpRequester delegate, final StreamingHttpRequest request) {
            return Single.succeeded(null).afterOnSubscribe(delayedClientCancels::add).concat(delegate().request(request).liftSync(target -> new Subscriber<StreamingHttpResponse>() {

                @Override
                public void onSubscribe(final Cancellable cancellable) {
                    target.onSubscribe(() -> {
                        delayedClientCancels.add(cancellable);
                        cancellable.cancel();
                    });
                }

                @Override
                public void onSuccess(final StreamingHttpResponse result) {
                    ClientTerminationSignal signal = OK.equals(result.status()) ? new ClientTerminationSignal(target, result) : new ClientTerminationSignal(target, new HttpResponseStatusException(result.status()));
                    delayedClientTermination.add(signal);
                    target.onSuccess(result);
                }

                @Override
                public void onError(final Throwable t) {
                    delayedClientTermination.add(new ClientTerminationSignal(target, t));
                    target.onError(t);
                }
            })).filter(Objects::nonNull).firstOrError().map(thing -> (StreamingHttpResponse) thing);
        }
    }).appendConnectionFactoryFilter(original -> new CountingConnectionFactory(original, connectionCount)).appendClientFilter(new TimeoutHttpRequesterFilter((req, ts) -> clientTimeout, true)).build();
}
Also used : Assertions.fail(org.junit.jupiter.api.Assertions.fail) Arrays(java.util.Arrays) StreamingHttpResponse(io.servicetalk.http.api.StreamingHttpResponse) Subscriber(io.servicetalk.concurrent.SingleSource.Subscriber) TimeoutException(java.util.concurrent.TimeoutException) Cancellable(io.servicetalk.concurrent.Cancellable) StreamingHttpRequester(io.servicetalk.http.api.StreamingHttpRequester) HttpServers.forAddress(io.servicetalk.http.netty.HttpServers.forAddress) FilterableStreamingHttpConnection(io.servicetalk.http.api.FilterableStreamingHttpConnection) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Single.succeeded(io.servicetalk.concurrent.api.Single.succeeded) Duration(java.time.Duration) HttpClient(io.servicetalk.http.api.HttpClient) StreamingHttpRequest(io.servicetalk.http.api.StreamingHttpRequest) AddressUtils.serverHostAndPort(io.servicetalk.transport.netty.internal.AddressUtils.serverHostAndPort) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) DelegatingConnectionFactory(io.servicetalk.client.api.DelegatingConnectionFactory) Nullable(javax.annotation.Nullable) MethodSource(org.junit.jupiter.params.provider.MethodSource) PrintWriter(java.io.PrintWriter) ConnectionFactory(io.servicetalk.client.api.ConnectionFactory) AddressUtils.localAddress(io.servicetalk.transport.netty.internal.AddressUtils.localAddress) ServerContext(io.servicetalk.transport.api.ServerContext) Single.defer(io.servicetalk.concurrent.api.Single.defer) Single(io.servicetalk.concurrent.api.Single) StringWriter(java.io.StringWriter) Collection(java.util.Collection) HttpClients.forSingleAddress(io.servicetalk.http.netty.HttpClients.forSingleAddress) HttpResponse(io.servicetalk.http.api.HttpResponse) TimeoutHttpRequesterFilter(io.servicetalk.http.utils.TimeoutHttpRequesterFilter) BlockingQueue(java.util.concurrent.BlockingQueue) AsyncCloseables.newCompositeCloseable(io.servicetalk.concurrent.api.AsyncCloseables.newCompositeCloseable) StreamingHttpClientFilter(io.servicetalk.http.api.StreamingHttpClientFilter) TimeoutHttpServiceFilter(io.servicetalk.http.utils.TimeoutHttpServiceFilter) OK(io.servicetalk.http.api.HttpResponseStatus.OK) InetSocketAddress(java.net.InetSocketAddress) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) Objects(java.util.Objects) Matchers.instanceOf(org.hamcrest.Matchers.instanceOf) CountDownLatch(java.util.concurrent.CountDownLatch) AfterEach(org.junit.jupiter.api.AfterEach) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) Matcher(org.hamcrest.Matcher) TransportObserver(io.servicetalk.transport.api.TransportObserver) Single.failed(io.servicetalk.concurrent.api.Single.failed) Matchers.is(org.hamcrest.Matchers.is) HttpResponseStatus(io.servicetalk.http.api.HttpResponseStatus) StreamingHttpRequester(io.servicetalk.http.api.StreamingHttpRequester) Cancellable(io.servicetalk.concurrent.Cancellable) TimeoutHttpServiceFilter(io.servicetalk.http.utils.TimeoutHttpServiceFilter) StreamingHttpClientFilter(io.servicetalk.http.api.StreamingHttpClientFilter) Single(io.servicetalk.concurrent.api.Single) Subscriber(io.servicetalk.concurrent.SingleSource.Subscriber) StreamingHttpRequest(io.servicetalk.http.api.StreamingHttpRequest) TimeoutHttpRequesterFilter(io.servicetalk.http.utils.TimeoutHttpRequesterFilter) StreamingHttpResponse(io.servicetalk.http.api.StreamingHttpResponse)

Example 5 with Subscriber

use of io.servicetalk.concurrent.SingleSource.Subscriber in project servicetalk by apple.

the class DefaultJerseyStreamingHttpRouter method handle.

@Override
public Single<StreamingHttpResponse> handle(final HttpServiceContext serviceCtx, final StreamingHttpRequest req, final StreamingHttpResponseFactory factory) {
    return new SubscribableSingle<StreamingHttpResponse>() {

        @Override
        protected void handleSubscribe(final Subscriber<? super StreamingHttpResponse> subscriber) {
            final DelayedCancellable delayedCancellable = new DelayedCancellable();
            DuplicateTerminateDetectorSingle<? super StreamingHttpResponse> dupSub = new DuplicateTerminateDetectorSingle<>(subscriber);
            try {
                dupSub.onSubscribe(delayedCancellable);
            } catch (Throwable cause) {
                handleExceptionFromOnSubscribe(dupSub, cause);
                return;
            }
            try {
                handle0(serviceCtx, req, factory, dupSub, delayedCancellable);
            } catch (final Throwable t) {
                safeOnError(dupSub, t);
            }
        }
    };
}
Also used : Subscriber(io.servicetalk.concurrent.SingleSource.Subscriber) SubscribableSingle(io.servicetalk.concurrent.api.internal.SubscribableSingle) DelayedCancellable(io.servicetalk.concurrent.internal.DelayedCancellable) StreamingHttpResponse(io.servicetalk.http.api.StreamingHttpResponse)

Aggregations

Subscriber (io.servicetalk.concurrent.SingleSource.Subscriber)6 Single (io.servicetalk.concurrent.api.Single)4 StreamingHttpResponse (io.servicetalk.http.api.StreamingHttpResponse)3 OK (io.servicetalk.http.api.HttpResponseStatus.OK)2 Collection (java.util.Collection)2 Assertions.fail (org.junit.jupiter.api.Assertions.fail)2 Buffer (io.servicetalk.buffer.api.Buffer)1 ConnectionFactory (io.servicetalk.client.api.ConnectionFactory)1 DelegatingConnectionFactory (io.servicetalk.client.api.DelegatingConnectionFactory)1 Cancellable (io.servicetalk.concurrent.Cancellable)1 IGNORE_CANCEL (io.servicetalk.concurrent.Cancellable.IGNORE_CANCEL)1 Processor (io.servicetalk.concurrent.CompletableSource.Processor)1 Subscription (io.servicetalk.concurrent.PublisherSource.Subscription)1 AsyncCloseables.newCompositeCloseable (io.servicetalk.concurrent.api.AsyncCloseables.newCompositeCloseable)1 Completable (io.servicetalk.concurrent.api.Completable)1 LegacyTestSingle (io.servicetalk.concurrent.api.LegacyTestSingle)1 Processors.newCompletableProcessor (io.servicetalk.concurrent.api.Processors.newCompletableProcessor)1 Publisher (io.servicetalk.concurrent.api.Publisher)1 Single.defer (io.servicetalk.concurrent.api.Single.defer)1 Single.failed (io.servicetalk.concurrent.api.Single.failed)1