/modules/repository-azure/src/main/java/org/elasticsearch/repositories/azure/executors/ReactorScheduledExecutorService.java

https://github.com/elasticsearch/elasticsearch · Java · 181 lines · 137 code · 31 blank · 13 comment · 2 complexity · ca745dca07bb35820440c5f4e6aeb1b6 MD5 · raw file

  1. /*
  2. * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
  3. * or more contributor license agreements. Licensed under the Elastic License
  4. * 2.0 and the Server Side Public License, v 1; you may not use this file except
  5. * in compliance with, at your election, the Elastic License 2.0 or the Server
  6. * Side Public License, v 1.
  7. */
  8. package org.elasticsearch.repositories.azure.executors;
  9. import org.apache.logging.log4j.LogManager;
  10. import org.apache.logging.log4j.Logger;
  11. import org.elasticsearch.common.util.concurrent.EsRejectedExecutionException;
  12. import org.elasticsearch.core.SuppressForbidden;
  13. import org.elasticsearch.core.TimeValue;
  14. import org.elasticsearch.threadpool.Scheduler;
  15. import org.elasticsearch.threadpool.ThreadPool;
  16. import java.util.Collections;
  17. import java.util.List;
  18. import java.util.concurrent.AbstractExecutorService;
  19. import java.util.concurrent.Callable;
  20. import java.util.concurrent.Delayed;
  21. import java.util.concurrent.ExecutorService;
  22. import java.util.concurrent.ScheduledExecutorService;
  23. import java.util.concurrent.ScheduledFuture;
  24. import java.util.concurrent.TimeUnit;
  25. import static org.elasticsearch.core.Strings.format;
  26. /**
  27. * Wrapper around {@link ThreadPool} that provides the necessary scheduling methods for a {@link reactor.core.scheduler.Scheduler} to
  28. * function. This allows injecting a custom Executor to the reactor schedulers factory and get fine grained control over the
  29. * thread resources used.
  30. */
  31. @SuppressForbidden(reason = "It wraps a ThreadPool and delegates all the work")
  32. public class ReactorScheduledExecutorService extends AbstractExecutorService implements ScheduledExecutorService {
  33. private final ThreadPool threadPool;
  34. private final String executorName;
  35. private final ExecutorService delegate;
  36. private final Logger logger = LogManager.getLogger(ReactorScheduledExecutorService.class);
  37. public ReactorScheduledExecutorService(ThreadPool threadPool, String executorName) {
  38. this.threadPool = threadPool;
  39. this.executorName = executorName;
  40. this.delegate = threadPool.executor(executorName);
  41. }
  42. @Override
  43. public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
  44. Scheduler.ScheduledCancellable schedule = threadPool.schedule(() -> {
  45. try {
  46. decorateCallable(callable).call();
  47. } catch (Exception e) {
  48. throw new RuntimeException(e);
  49. }
  50. }, new TimeValue(delay, unit), executorName);
  51. return new ReactorFuture<>(schedule);
  52. }
  53. public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
  54. Runnable decoratedCommand = decorateRunnable(command);
  55. Scheduler.ScheduledCancellable schedule = threadPool.schedule(decoratedCommand, new TimeValue(delay, unit), executorName);
  56. return new ReactorFuture<>(schedule);
  57. }
  58. @Override
  59. public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
  60. Runnable decoratedCommand = decorateRunnable(command);
  61. return threadPool.scheduler().scheduleAtFixedRate(() -> {
  62. try {
  63. delegate.execute(decoratedCommand);
  64. } catch (EsRejectedExecutionException e) {
  65. if (e.isExecutorShutdown()) {
  66. logger.debug(
  67. () -> format(
  68. "could not schedule execution of [%s] on [%s] as executor is shut down",
  69. decoratedCommand,
  70. executorName
  71. ),
  72. e
  73. );
  74. } else {
  75. throw e;
  76. }
  77. }
  78. }, initialDelay, period, unit);
  79. }
  80. @Override
  81. public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
  82. Runnable decorateRunnable = decorateRunnable(command);
  83. Scheduler.Cancellable cancellable = threadPool.scheduleWithFixedDelay(decorateRunnable, new TimeValue(delay, unit), executorName);
  84. return new ReactorFuture<>(cancellable);
  85. }
  86. @Override
  87. public void shutdown() {
  88. // No-op
  89. }
  90. @Override
  91. public List<Runnable> shutdownNow() {
  92. return Collections.emptyList();
  93. }
  94. @Override
  95. public boolean isShutdown() {
  96. return delegate.isShutdown();
  97. }
  98. @Override
  99. public boolean isTerminated() {
  100. return delegate.isTerminated();
  101. }
  102. @Override
  103. public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
  104. return delegate.awaitTermination(timeout, unit);
  105. }
  106. @Override
  107. public void execute(Runnable command) {
  108. delegate.execute(decorateRunnable(command));
  109. }
  110. protected Runnable decorateRunnable(Runnable command) {
  111. return command;
  112. }
  113. protected <V> Callable<V> decorateCallable(Callable<V> callable) {
  114. return callable;
  115. }
  116. private static final class ReactorFuture<V> implements ScheduledFuture<V> {
  117. private final Scheduler.Cancellable cancellable;
  118. private ReactorFuture(Scheduler.Cancellable cancellable) {
  119. this.cancellable = cancellable;
  120. }
  121. @Override
  122. public long getDelay(TimeUnit unit) {
  123. throw new UnsupportedOperationException();
  124. }
  125. @Override
  126. public int compareTo(Delayed o) {
  127. throw new UnsupportedOperationException();
  128. }
  129. @Override
  130. public boolean cancel(boolean mayInterruptIfRunning) {
  131. return cancellable.cancel();
  132. }
  133. @Override
  134. public boolean isCancelled() {
  135. return cancellable.isCancelled();
  136. }
  137. @Override
  138. public boolean isDone() {
  139. return cancellable.isCancelled();
  140. }
  141. @Override
  142. public V get() {
  143. throw new UnsupportedOperationException();
  144. }
  145. @Override
  146. public V get(long timeout, TimeUnit unit) {
  147. throw new UnsupportedOperationException();
  148. }
  149. }
  150. }