Allow binding FanOutExecutor instead of WorkQueue

At Google, we are not using WorkQueue heavily because we don't
need the extra functionality it provides and it comes at additional
complexity. Instead, we use the FanOutExecutor.

This change allows using WorkQueue or FanOutExecutor based on
initialization.

Change-Id: I71ed23870d674bbaa0e1d2dde3204e93aea8af33
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/Module.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/Module.java
index c34baf0..3ae0355 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/Module.java
@@ -17,6 +17,8 @@
 import static com.google.gerrit.server.project.ProjectResource.PROJECT_KIND;
 import static com.googlesource.gerrit.plugins.reviewers.ModifyReviewersConfigCapability.MODIFY_REVIEWERS_CONFIG;
 
+import com.google.gerrit.common.UsedAt;
+import com.google.gerrit.common.UsedAt.Project;
 import com.google.gerrit.extensions.annotations.Exports;
 import com.google.gerrit.extensions.config.CapabilityDefinition;
 import com.google.gerrit.extensions.config.FactoryModule;
@@ -36,22 +38,48 @@
 import com.googlesource.gerrit.plugins.reviewers.config.GlobalConfig;
 
 public class Module extends FactoryModule {
+  enum ThreadPool {
+    DIRECT,
+    WORK_QUEUE,
+    FAN_OUT
+  }
+
+  static class ForTest extends Module {
+    ForTest() {
+      super(true, false, ThreadPool.DIRECT);
+    }
+  }
+
   private final boolean enableREST;
   private final boolean suggestOnly;
+  private final ThreadPool threadPool;
 
   @Inject
   public Module(GlobalConfig cfg) {
-    this(cfg.enableREST(), cfg.suggestOnly());
+    this(cfg.enableREST(), cfg.suggestOnly(), ThreadPool.WORK_QUEUE);
   }
 
-  public Module(boolean enableREST, boolean suggestOnly) {
+  @UsedAt(Project.GOOGLE)
+  public Module(boolean enableREST, boolean suggestOnly, ThreadPool threadPool) {
     this.enableREST = enableREST;
     this.suggestOnly = suggestOnly;
+    this.threadPool = threadPool;
   }
 
   @Override
   protected void configure() {
-    bindWorkQueue();
+    switch (threadPool) {
+      case DIRECT:
+        bind(ReviewerWorkQueue.class).to(ReviewerWorkQueue.Direct.class);
+        break;
+      case WORK_QUEUE:
+        bind(ReviewerWorkQueue.class).to(ReviewerWorkQueue.Scheduled.class);
+        break;
+      case FAN_OUT:
+        bind(ReviewerWorkQueue.class).to(ReviewerWorkQueue.ScheduledFanOut.class);
+      default:
+        break;
+    }
     bind(CapabilityDefinition.class)
         .annotatedWith(Exports.named(MODIFY_REVIEWERS_CONFIG))
         .to(ModifyReviewersConfigCapability.class);
@@ -95,8 +123,4 @@
         });
     install(new ConfigModule());
   }
-
-  protected void bindWorkQueue() {
-    bind(ReviewerWorkQueue.class).to(ReviewerWorkQueue.Scheduled.class);
-  }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewerWorkQueue.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewerWorkQueue.java
index d4241c7..e47f9a6 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewerWorkQueue.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewerWorkQueue.java
@@ -16,13 +16,16 @@
 
 import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
 
+import com.google.gerrit.server.FanOutExecutor;
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.inject.Inject;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
 
 interface ReviewerWorkQueue {
   void submit(AddReviewers addReviewers);
 
-  static class Scheduled implements ReviewerWorkQueue {
+  class Scheduled implements ReviewerWorkQueue {
     private final WorkQueue workQueue;
 
     @Inject
@@ -36,11 +39,25 @@
     }
   }
 
-  static class Direct implements ReviewerWorkQueue {
-
+  class Direct implements ReviewerWorkQueue {
     @Override
     public void submit(AddReviewers addReviewers) {
       directExecutor().execute(addReviewers);
     }
   }
+
+  class ScheduledFanOut implements ReviewerWorkQueue {
+    private final ExecutorService executor;
+
+    @Inject
+    ScheduledFanOut(@FanOutExecutor ExecutorService executor) {
+      this.executor = executor;
+    }
+
+    @Override
+    public void submit(AddReviewers addReviewers) {
+      @SuppressWarnings("unused")
+      Future<?> ignored = executor.submit(addReviewers);
+    }
+  }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/TestModule.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/TestModule.java
deleted file mode 100644
index 380280a..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/TestModule.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.reviewers;
-
-public class TestModule extends Module {
-
-  public TestModule() {
-    super(true, false);
-  }
-
-  @Override
-  protected void bindWorkQueue() {
-    bind(ReviewerWorkQueue.class).to(ReviewerWorkQueue.Direct.class);
-  }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/reviewers/ReviewersIT.java b/src/test/java/com/googlesource/gerrit/plugins/reviewers/ReviewersIT.java
index e6fb981..bedd4de 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/reviewers/ReviewersIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/reviewers/ReviewersIT.java
@@ -40,7 +40,9 @@
 import org.junit.Test;
 
 @NoHttpd
-@TestPlugin(name = "reviewers", sysModule = "com.googlesource.gerrit.plugins.reviewers.TestModule")
+@TestPlugin(
+    name = "reviewers",
+    sysModule = "com.googlesource.gerrit.plugins.reviewers.Module$ForTest")
 public class ReviewersIT extends AbstractReviewersPluginTest {
 
   @Test