1919import com .google .api .gax .bundling .FlowController ;
2020import com .google .api .gax .core .RetrySettings ;
2121import com .google .api .gax .grpc .BundlingSettings ;
22+ import com .google .api .gax .grpc .ExecutorProvider ;
23+ import com .google .api .gax .grpc .InstantiatingExecutorProvider ;
2224import com .google .auth .Credentials ;
2325import com .google .auth .oauth2 .GoogleCredentials ;
2426import com .google .common .base .Optional ;
2830import com .google .common .util .concurrent .Futures ;
2931import com .google .common .util .concurrent .ListenableFuture ;
3032import com .google .common .util .concurrent .SettableFuture ;
31- import com .google .common .util .concurrent .ThreadFactoryBuilder ;
3233import com .google .pubsub .v1 .PublishRequest ;
3334import com .google .pubsub .v1 .PublishResponse ;
3435import com .google .pubsub .v1 .PublisherGrpc ;
4344import io .grpc .netty .NegotiationType ;
4445import io .grpc .netty .NettyChannelBuilder ;
4546import java .io .IOException ;
47+ import java .util .ArrayList ;
4648import java .util .Iterator ;
4749import java .util .LinkedList ;
4850import java .util .List ;
49- import java .util .concurrent .Executors ;
5051import java .util .concurrent .ScheduledExecutorService ;
5152import java .util .concurrent .ScheduledFuture ;
5253import java .util .concurrent .ThreadLocalRandom ;
@@ -118,8 +119,6 @@ public static long getApiMaxBundleBytes() {
118119 return 10L * 1000L * 1000L ; // 10 megabytes (https://en.wikipedia.org/wiki/Megabyte)
119120 }
120121
121- private static final int DEFAULT_MIN_THREAD_POOL_SIZE = 5 ;
122-
123122 private static final Logger logger = LoggerFactory .getLogger (Publisher .class );
124123
125124 private final String topic ;
@@ -143,6 +142,7 @@ public static long getApiMaxBundleBytes() {
143142
144143 private final ScheduledExecutorService executor ;
145144 private final AtomicBoolean shutdown ;
145+ private final List <AutoCloseable > closeables = new ArrayList <>();
146146 private final MessagesWaiter messagesWaiter ;
147147 private ScheduledFuture <?> currentAlarmFuture ;
148148
@@ -160,15 +160,16 @@ private Publisher(Builder builder) throws IOException {
160160 messagesBundleLock = new ReentrantLock ();
161161 activeAlarm = new AtomicBoolean (false );
162162 int numCores = Math .max (1 , Runtime .getRuntime ().availableProcessors ());
163- executor =
164- builder .executor .isPresent ()
165- ? builder .executor .get ()
166- : Executors .newScheduledThreadPool (
167- numCores * DEFAULT_MIN_THREAD_POOL_SIZE ,
168- new ThreadFactoryBuilder ()
169- .setDaemon (true )
170- .setNameFormat ("cloud-pubsub-publisher-thread-%d" )
171- .build ());
163+ executor = builder .executorProvider .getExecutor ();
164+ if (builder .executorProvider .shouldAutoClose ()) {
165+ closeables .add (
166+ new AutoCloseable () {
167+ @ Override
168+ public void close () throws IOException {
169+ executor .shutdown ();
170+ }
171+ });
172+ }
172173 channels = new Channel [numCores ];
173174 channelIndex = new AtomicRoundRobin (channels .length );
174175 for (int i = 0 ; i < numCores ; i ++) {
@@ -480,7 +481,7 @@ public PublisherStats getStats() {
480481 * should be invoked prior to deleting the {@link Publisher} object in order to ensure that no
481482 * pending messages are lost.
482483 */
483- public void shutdown () {
484+ public void shutdown () throws Exception {
484485 if (shutdown .getAndSet (true )) {
485486 throw new IllegalStateException ("Cannot shut down a publisher already shut-down." );
486487 }
@@ -489,6 +490,9 @@ public void shutdown() {
489490 }
490491 publishAllOutstanding ();
491492 messagesWaiter .waitNoMessages ();
493+ for (AutoCloseable closeable : closeables ) {
494+ closeable .close ();
495+ }
492496 }
493497
494498 private boolean hasBundlingBytes () {
@@ -550,6 +554,12 @@ public static final class Builder {
550554 .setMaxRpcTimeout (DEFAULT_RPC_TIMEOUT )
551555 .build ();
552556
557+ private static final int THREADS_PER_CPU = 5 ;
558+ static final ExecutorProvider DEFAULT_EXECUTOR_PROVIDER =
559+ InstantiatingExecutorProvider .newBuilder ()
560+ .setExecutorThreadCount (THREADS_PER_CPU * Runtime .getRuntime ().availableProcessors ())
561+ .build ();
562+
553563 String topic ;
554564
555565 // Bundling options
@@ -566,7 +576,7 @@ public static final class Builder {
566576 Optional <ManagedChannelBuilder <? extends ManagedChannelBuilder <?>>> channelBuilder =
567577 Optional .absent ();
568578
569- Optional < ScheduledExecutorService > executor = Optional . absent () ;
579+ ExecutorProvider executorProvider = DEFAULT_EXECUTOR_PROVIDER ;
570580
571581 /** Constructs a new {@link Builder} using the given topic. */
572582 public static Builder newBuilder (TopicName topic ) {
@@ -656,8 +666,8 @@ public Builder setRetrySettings(RetrySettings retrySettings) {
656666 }
657667
658668 /** Gives the ability to set a custom executor to be used by the library. */
659- public Builder setExecutor ( ScheduledExecutorService executor ) {
660- this .executor = Optional . of ( Preconditions .checkNotNull (executor ) );
669+ public Builder setExecutorProvider ( ExecutorProvider executorProvider ) {
670+ this .executorProvider = Preconditions .checkNotNull (executorProvider );
661671 return this ;
662672 }
663673
0 commit comments