Skip to content

Commit

Permalink
Ensure that MongoClient's EventLoopGroup is shut down during context …
Browse files Browse the repository at this point in the history
…close

See gh-16087
  • Loading branch information
nosan authored and wilkinsona committed Apr 2, 2019
1 parent 02b24b6 commit ee7bed1
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@
import javax.annotation.PreDestroy;

import com.mongodb.MongoClientSettings;
import com.mongodb.MongoClientSettings.Builder;
import com.mongodb.connection.netty.NettyStreamFactoryFactory;
import com.mongodb.reactivestreams.client.MongoClient;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import reactor.core.publisher.Flux;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
Expand Down Expand Up @@ -77,23 +81,51 @@ public MongoClient reactiveStreamsMongoClient(MongoProperties properties,
}

@Configuration
@ConditionalOnClass(SocketChannel.class)
@ConditionalOnClass({ SocketChannel.class, NioEventLoopGroup.class })
static class NettyDriverConfiguration {

@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public MongoClientSettingsBuilderCustomizer nettyDriverCustomizer(
ObjectProvider<MongoClientSettings> settings) {
return (builder) -> {
if (!isStreamFactoryFactoryDefined(settings.getIfAvailable())) {
builder.streamFactoryFactory(
NettyStreamFactoryFactory.builder().build());
}
};
return new EventLoopGroupMongoClientSettingsBuilderCustomizer(settings);
}

private boolean isStreamFactoryFactoryDefined(MongoClientSettings settings) {
return settings != null && settings.getStreamFactoryFactory() != null;
private static final class EventLoopGroupMongoClientSettingsBuilderCustomizer
implements MongoClientSettingsBuilderCustomizer, DisposableBean {

private final ObjectProvider<MongoClientSettings> settings;

private EventLoopGroup eventLoopGroup;

private EventLoopGroupMongoClientSettingsBuilderCustomizer(
ObjectProvider<MongoClientSettings> settings) {
this.settings = settings;
}

@Override
public void customize(Builder builder) {
if (!isStreamFactoryFactoryDefined(this.settings.getIfAvailable())) {
NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
this.eventLoopGroup = eventLoopGroup;
builder.streamFactoryFactory(NettyStreamFactoryFactory.builder()
.eventLoopGroup(eventLoopGroup).build());
}
}

@Override
public void destroy() {
EventLoopGroup eventLoopGroup = this.eventLoopGroup;
if (eventLoopGroup != null) {
eventLoopGroup.shutdownGracefully().awaitUninterruptibly();
this.eventLoopGroup = null;
}
}

private boolean isStreamFactoryFactoryDefined(MongoClientSettings settings) {
return settings != null && settings.getStreamFactoryFactory() != null;
}

}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,6 +17,7 @@
package org.springframework.boot.autoconfigure.mongo;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

import com.mongodb.MongoClientSettings;
import com.mongodb.ReadPreference;
Expand All @@ -25,6 +26,7 @@
import com.mongodb.connection.StreamFactoryFactory;
import com.mongodb.connection.netty.NettyStreamFactoryFactory;
import com.mongodb.reactivestreams.client.MongoClient;
import io.netty.channel.EventLoopGroup;
import org.junit.Test;

import org.springframework.boot.autoconfigure.AutoConfigurations;
Expand Down Expand Up @@ -89,11 +91,17 @@ public void optionsSslConfig() {

@Test
public void nettyStreamFactoryFactoryIsConfiguredAutomatically() {
AtomicReference<EventLoopGroup> capture = new AtomicReference<>();
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(MongoClient.class);
assertThat(getSettings(context).getStreamFactoryFactory())
.isInstanceOf(NettyStreamFactoryFactory.class);
StreamFactoryFactory factory = getSettings(context).getStreamFactoryFactory();
assertThat(factory).isInstanceOf(NettyStreamFactoryFactory.class);
capture.set((EventLoopGroup) ReflectionTestUtils.getField(factory,
"eventLoopGroup"));
assertThat(capture.get()).isNotNull();
assertThat(capture.get().isShutdown()).isFalse();
});
assertThat(capture.get().isShutdown()).isTrue();
}

@Test
Expand Down

0 comments on commit ee7bed1

Please sign in to comment.