Fix: The email notification of review comments gets stuck.
Sometimes it is found that one thread goes stuck when waiting
for an answer from the SMTP server.
Fixed. Enable user to
-config the timeout value of opening a socket connected to a remote
SMTP server.
-config the worker-thread pool size of executor used for sending out
review comments notification when it is not enough to dedicate only
one thread.
-config the default size of the background execution thread pool when
one thread is not enough to handle miscellaneous tasks including
sending out every kind email notification.
Change-Id: Id8177b374f7049cfac617c50e66b2c83ae71641b
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index c5ef758..038d946 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -2412,6 +2412,16 @@
+
Default is true, to execute project specific rules.
+[[execution]]Section execution
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+[[execution.defaultThreadPoolSize]]execution.defaultThreadPoolSize::
++
+The default size of the background execution thread pool in
+which miscellaneous tasks are handled.
++
+Default is 1.
+
[[sendemail]]Section sendemail
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2422,6 +2432,26 @@
+
By default, true, allowing notifications to be sent.
+[[sendemail.connectTimeout]]sendemail.connectTimeout::
++
+The connection timeout of opening a socket connected to a
+remote SMTP server.
++
+Values can be specified using standard time unit abbreviations
+('ms', 'sec', 'min', etc.).
+If no unit is specified, milliseconds is assumed.
++
+Default is 0. A timeout of zero is interpreted as an infinite
+timeout. The connection will then block until established or
+an error occurs.
+
+[[sendemail.threadPoolSize]]sendemail.threadPoolSize::
++
+Maximum size of thread pool in which the review comments
+notifications are sent out asynchronously.
++
+By default, 1.
+
[[sendemail.from]]sendemail.from::
+
Designates what name and address Gerrit will place in the From
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/EmailReviewComments.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/EmailReviewComments.java
index 11a9edd..eea2f48 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/EmailReviewComments.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/EmailReviewComments.java
@@ -23,7 +23,8 @@
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.change.PostReview.NotifyHandling;
-import com.google.gerrit.server.git.WorkQueue;
+import com.google.gerrit.server.git.EmailReviewCommentsExecutor;
+import com.google.gerrit.server.git.WorkQueue.Executor;
import com.google.gerrit.server.mail.CommentSender;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.util.RequestContext;
@@ -55,7 +56,7 @@
List<PatchLineComment> comments);
}
- private final WorkQueue workQueue;
+ private final Executor sendEmailsExecutor;
private final PatchSetInfoFactory patchSetInfoFactory;
private final CommentSender.Factory commentSenderFactory;
private final SchemaFactory<ReviewDb> schemaFactory;
@@ -71,7 +72,7 @@
@Inject
EmailReviewComments (
- WorkQueue workQueue,
+ @EmailReviewCommentsExecutor final Executor executor,
PatchSetInfoFactory patchSetInfoFactory,
CommentSender.Factory commentSenderFactory,
SchemaFactory<ReviewDb> schemaFactory,
@@ -82,7 +83,7 @@
@Assisted Account.Id authorId,
@Assisted ChangeMessage message,
@Assisted List<PatchLineComment> comments) {
- this.workQueue = workQueue;
+ this.sendEmailsExecutor = executor;
this.patchSetInfoFactory = patchSetInfoFactory;
this.commentSenderFactory = commentSenderFactory;
this.schemaFactory = schemaFactory;
@@ -96,7 +97,7 @@
}
void sendAsync() {
- workQueue.getDefaultQueue().submit(this);
+ sendEmailsExecutor.submit(this);
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/EmailReviewCommentsExecutor.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/EmailReviewCommentsExecutor.java
new file mode 100644
index 0000000..1581ec48
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/EmailReviewCommentsExecutor.java
@@ -0,0 +1,30 @@
+// Copyright (C) 2014 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.google.gerrit.server.git;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.inject.BindingAnnotation;
+
+import java.lang.annotation.Retention;
+
+/**
+ * Marker on the global {@link WorkQueue.Executor} used by
+ * {@link EmailReviewComments}.
+ */
+@Retention(RUNTIME)
+@BindingAnnotation
+public @interface EmailReviewCommentsExecutor {
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsExecutorModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsExecutorModule.java
index 1cbd227..81ce05d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsExecutorModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsExecutorModule.java
@@ -47,6 +47,15 @@
@Provides
@Singleton
+ @EmailReviewCommentsExecutor
+ public WorkQueue.Executor createEmailReviewCommentsExecutor(
+ @GerritServerConfig Config config, WorkQueue queues) {
+ int poolSize = config.getInt("sendemail", null, "threadPoolSize", 1);
+ return queues.createQueue(poolSize, "EmailReviewComments");
+ }
+
+ @Provides
+ @Singleton
@ChangeUpdateExecutor
public ListeningExecutorService createChangeUpdateExecutor(@GerritServerConfig Config config) {
int poolSize = config.getInt("receive", null, "changeUpdateThreads", 1);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
index 90c5335..d7a2cf4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
@@ -18,10 +18,12 @@
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.reviewdb.client.Project.NameKey;
+import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.util.IdGenerator;
import com.google.inject.Inject;
import com.google.inject.Singleton;
+import org.eclipse.jgit.lib.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -83,19 +85,21 @@
};
private Executor defaultQueue;
+ private int defaultQueueSize;
private final IdGenerator idGenerator;
private final CopyOnWriteArrayList<Executor> queues;
@Inject
- WorkQueue(final IdGenerator idGenerator) {
+ WorkQueue(final IdGenerator idGenerator, @GerritServerConfig final Config cfg) {
this.idGenerator = idGenerator;
this.queues = new CopyOnWriteArrayList<Executor>();
+ defaultQueueSize = cfg.getInt("execution", "defaultThreadPoolSize", 1);
}
/** Get the default work queue, for miscellaneous tasks. */
public synchronized Executor getDefaultQueue() {
if (defaultQueue == null) {
- defaultQueue = createQueue(1, "WorkQueue");
+ defaultQueue = createQueue(defaultQueueSize, "WorkQueue");
}
return defaultQueue;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/SmtpEmailSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/SmtpEmailSender.java
index 89fc6b9..48e2d03 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/SmtpEmailSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/SmtpEmailSender.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.mail;
+import com.google.common.primitives.Ints;
import com.google.gerrit.common.Version;
import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.server.config.ConfigUtil;
@@ -39,10 +40,14 @@
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
/** Sends email via a nearby SMTP server. */
@Singleton
public class SmtpEmailSender implements EmailSender {
+ /** The socket's connect timeout (0 = infinite timeout) */
+ private static final int DEFAULT_CONNECT_TIMEOUT = 0;
+
public static class Module extends AbstractModule {
@Override
protected void configure() {
@@ -55,6 +60,7 @@
}
private final boolean enabled;
+ private final int connectTimeout;
private String smtpHost;
private int smtpPort;
@@ -69,6 +75,10 @@
@Inject
SmtpEmailSender(@GerritServerConfig final Config cfg) {
enabled = cfg.getBoolean("sendemail", null, "enable", true);
+ connectTimeout =
+ Ints.checkedCast(ConfigUtil.getTimeUnit(cfg, "sendemail", null,
+ "connectTimeout", DEFAULT_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS));
+
smtpHost = cfg.getString("sendemail", null, "smtpserver");
if (smtpHost == null) {
@@ -239,6 +249,7 @@
}
try {
+ client.setConnectTimeout(connectTimeout);
client.connect(smtpHost, smtpPort);
if (!SMTPReply.isPositiveCompletion(client.getReplyCode())) {
throw new EmailException("SMTP server rejected connection");