use of io.servicetalk.concurrent.api.CompositeCloseable in project servicetalk by apple.
the class GrpcRouter method bind.
Single<GrpcServerContext> bind(final ServerBinder binder, final GrpcExecutionContext executionContext) {
final CompositeCloseable closeable = AsyncCloseables.newCompositeCloseable();
final Map<String, StreamingHttpService> allRoutes = new HashMap<>();
populateRoutes(executionContext, allRoutes, routes, closeable, executionStrategies);
populateRoutes(executionContext, allRoutes, streamingRoutes, closeable, executionStrategies);
populateRoutes(executionContext, allRoutes, blockingRoutes, closeable, executionStrategies);
populateRoutes(executionContext, allRoutes, blockingStreamingRoutes, closeable, executionStrategies);
// TODO: Optimize to bind a specific programming model service based on routes
return binder.bindStreaming(new StreamingHttpService() {
@Override
public Single<StreamingHttpResponse> handle(final HttpServiceContext ctx, final StreamingHttpRequest request, final StreamingHttpResponseFactory responseFactory) {
final StreamingHttpService service;
if (!POST.equals(request.method()) || (service = allRoutes.get(request.path())) == null) {
return NOT_FOUND_SERVICE.handle(ctx, request, responseFactory);
} else {
return service.handle(ctx, request, responseFactory);
}
}
@Override
public Completable closeAsync() {
return closeable.closeAsync();
}
@Override
public Completable closeAsyncGracefully() {
return closeable.closeAsyncGracefully();
}
}).map(httpServerContext -> new DefaultGrpcServerContext(httpServerContext, executionContext));
}
use of io.servicetalk.concurrent.api.CompositeCloseable in project servicetalk by apple.
the class HttpRequestEncoderTest method protocolPayloadEndOutboundShouldNotTriggerOnFailedFlush.
@Test
void protocolPayloadEndOutboundShouldNotTriggerOnFailedFlush() throws Exception {
AtomicReference<CloseHandler> closeHandlerRef = new AtomicReference<>();
try (CompositeCloseable resources = newCompositeCloseable()) {
Processor serverCloseTrigger = newCompletableProcessor();
CountDownLatch serverChannelLatch = new CountDownLatch(1);
AtomicReference<Channel> serverChannelRef = new AtomicReference<>();
ReadOnlyTcpServerConfig sConfig = new TcpServerConfig().asReadOnly();
ServerContext serverContext = resources.prepend(TcpServerBinder.bind(localAddress(0), sConfig, false, SEC, null, (channel, observer) -> DefaultNettyConnection.initChannel(channel, SEC.bufferAllocator(), SEC.executor(), SEC.ioExecutor(), forPipelinedRequestResponse(false, channel.config()), defaultFlushStrategy(), null, new TcpServerChannelInitializer(sConfig, observer).andThen(channel2 -> {
serverChannelRef.compareAndSet(null, channel2);
serverChannelLatch.countDown();
}), defaultStrategy(), mock(Protocol.class), observer, false, __ -> false), connection -> {
}).toFuture().get());
ReadOnlyHttpClientConfig cConfig = new HttpClientConfig().asReadOnly();
assert cConfig.h1Config() != null;
NettyConnection<Object, Object> conn = resources.prepend(TcpConnector.connect(null, serverHostAndPort(serverContext), cConfig.tcpConfig(), false, CEC, (channel, connectionObserver) -> {
CloseHandler closeHandler = spy(forPipelinedRequestResponse(true, channel.config()));
closeHandlerRef.compareAndSet(null, closeHandler);
return DefaultNettyConnection.initChannel(channel, CEC.bufferAllocator(), CEC.executor(), CEC.ioExecutor(), closeHandler, defaultFlushStrategy(), null, new TcpClientChannelInitializer(cConfig.tcpConfig(), connectionObserver).andThen(new HttpClientChannelInitializer(getByteBufAllocator(CEC.bufferAllocator()), cConfig.h1Config(), closeHandler)).andThen(channel2 -> channel2.pipeline().addLast(new ChannelInboundHandlerAdapter() {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
// Propagate the user event in the pipeline before
// triggering the test condition.
ctx.fireUserEventTriggered(evt);
if (evt instanceof ChannelInputShutdownReadComplete) {
serverCloseTrigger.onComplete();
}
}
})), defaultStrategy(), HTTP_1_1, connectionObserver, true, __ -> false);
}, NoopTransportObserver.INSTANCE).toFuture().get());
// The server needs to wait to close the conneciton until after the client has established the connection.
serverChannelLatch.await();
Channel serverChannel = serverChannelRef.get();
assertNotNull(serverChannel);
assumeFalse(serverChannel instanceof NioSocketChannel, "Windows doesn't emit ChannelInputShutdownReadComplete. Investigation Required.");
((SocketChannel) serverChannel).config().setSoLinger(0);
// Close and send RST concurrently with client write
serverChannel.close();
StreamingHttpRequest request = reqRespFactory.post("/closeme");
fromSource(serverCloseTrigger).toFuture().get();
Completable write = conn.write(from(request, allocator.fromAscii("Bye"), EmptyHttpHeaders.INSTANCE));
assertThrows(ExecutionException.class, () -> write.toFuture().get());
CloseHandler closeHandler = closeHandlerRef.get();
assertNotNull(closeHandler);
verify(closeHandler, never()).protocolPayloadEndOutbound(any(), any());
}
}
use of io.servicetalk.concurrent.api.CompositeCloseable in project servicetalk by apple.
the class HttpConnectionEmptyPayloadTest method headRequestContentEmpty.
@Test
void headRequestContentEmpty() throws Exception {
try (CompositeCloseable closeable = AsyncCloseables.newCompositeCloseable()) {
final int expectedContentLength = 128;
byte[] expectedPayload = new byte[expectedContentLength];
ThreadLocalRandom.current().nextBytes(expectedPayload);
ServerContext serverContext = closeable.merge(HttpServers.forAddress(localAddress(0)).ioExecutor(executionContextRule.ioExecutor()).executionStrategy(offloadNever()).listenStreamingAndAwait((ctx, req, factory) -> {
StreamingHttpResponse resp = factory.ok().payloadBody(from(HEAD.equals(req.method()) ? EMPTY_BUFFER : ctx.executionContext().bufferAllocator().newBuffer(expectedContentLength).writeBytes(expectedPayload)));
resp.addHeader(CONTENT_LENGTH, String.valueOf(expectedContentLength));
return succeeded(resp);
}));
StreamingHttpClient client = closeable.merge(forResolvedAddress(serverHostAndPort(serverContext)).ioExecutor(executionContextRule.ioExecutor()).protocols(h1().maxPipelinedRequests(3).build()).executor(executionContextRule.executor()).executionStrategy(defaultStrategy()).buildStreaming());
StreamingHttpConnection connection = closeable.merge(client.reserveConnection(client.get("/")).toFuture().get());
// Request HEAD, GET, HEAD to verify that we can keep reading data despite a HEAD request providing a hint
// about content-length (and not actually providing the content).
Single<StreamingHttpResponse> response1Single = connection.request(connection.newRequest(HEAD, "/"));
Single<StreamingHttpResponse> response2Single = connection.request(connection.get("/"));
Single<StreamingHttpResponse> response3Single = connection.request(connection.newRequest(HEAD, "/"));
StreamingHttpResponse response = awaitIndefinitelyNonNull(response1Single);
assertEquals(OK, response.status());
CharSequence contentLength = response.headers().get(CONTENT_LENGTH);
assertNotNull(contentLength);
assertEquals(expectedContentLength, parseInt(contentLength.toString()));
// Drain the current response content so we will be able to read the next response.
response.messageBody().ignoreElements().toFuture().get();
response = awaitIndefinitelyNonNull(response2Single);
assertEquals(OK, response.status());
contentLength = response.headers().get(CONTENT_LENGTH);
assertNotNull(contentLength);
assertEquals(expectedContentLength, parseInt(contentLength.toString()));
Buffer buffer = awaitIndefinitelyNonNull(response.payloadBody().collect(() -> connection.connectionContext().executionContext().bufferAllocator().newBuffer(), Buffer::writeBytes));
byte[] actualBytes = new byte[buffer.readableBytes()];
buffer.readBytes(actualBytes);
assertArrayEquals(expectedPayload, actualBytes);
response = awaitIndefinitelyNonNull(response3Single);
assertEquals(OK, response.status());
contentLength = response.headers().get(CONTENT_LENGTH);
assertNotNull(contentLength);
assertEquals(expectedContentLength, parseInt(contentLength.toString()));
response.messageBody().ignoreElements().toFuture().get();
}
}
use of io.servicetalk.concurrent.api.CompositeCloseable in project servicetalk by apple.
the class HttpOffloadingTest method afterTest.
@AfterEach
void afterTest() throws Exception {
CompositeCloseable closeables = newCompositeCloseable();
Stream.of(httpConnection, client, serverContext).filter(Objects::nonNull).map(AsyncCloseable.class::cast).forEach(closeables::append);
closeables.close();
}
use of io.servicetalk.concurrent.api.CompositeCloseable in project servicetalk by apple.
the class BackendsStarter method main.
public static void main(String[] args) throws Exception {
// Create an AutoCloseable representing all resources used in this example.
try (CompositeCloseable resources = newCompositeCloseable()) {
// Shared IoExecutor for the application.
IoExecutor ioExecutor = resources.prepend(createIoExecutor());
// This is a single Completable used to await closing of all backends started by this class. It is used to
// provide a way to not let main() exit.
Completable allServicesOnClose = completed();
BackendStarter starter = new BackendStarter(ioExecutor, resources);
final ServerContext recommendationService = starter.start(RECOMMENDATIONS_BACKEND_ADDRESS.port(), RECOMMENDATION_SERVICE_NAME, newRecommendationsService());
allServicesOnClose = allServicesOnClose.merge(recommendationService.onClose());
final ServerContext metadataService = starter.start(METADATA_BACKEND_ADDRESS.port(), METADATA_SERVICE_NAME, newMetadataService());
allServicesOnClose = allServicesOnClose.merge(metadataService.onClose());
final ServerContext userService = starter.start(USER_BACKEND_ADDRESS.port(), USER_SERVICE_NAME, newUserService());
allServicesOnClose = allServicesOnClose.merge(userService.onClose());
final ServerContext ratingService = starter.start(RATINGS_BACKEND_ADDRESS.port(), RATING_SERVICE_NAME, newRatingService());
allServicesOnClose = allServicesOnClose.merge(ratingService.onClose());
// Await termination of all backends started by this class.
allServicesOnClose.toFuture().get();
}
}
Aggregations