From 6dd03bf6e423fb2e8aaf871f7fa0ff093a35564f Mon Sep 17 00:00:00 2001 From: Alex Earl Date: Fri, 1 Nov 2024 11:06:07 -0700 Subject: [PATCH] JENKINS-73740: Allow admins to disable throttling Add global configuration to disable throttling. --- .../emailext/ExtendedEmailPublisher.java | 10 +++- .../ExtendedEmailPublisherDescriptor.java | 14 ++++++ .../ExtendedEmailPublisher/global.groovy | 3 ++ .../help/globalConfig/throttlingEnabled.html | 5 ++ .../emailext/ExtendedEmailPublisherTest.java | 49 ++++++++++++++----- 5 files changed, 68 insertions(+), 13 deletions(-) create mode 100644 src/main/webapp/help/globalConfig/throttlingEnabled.html diff --git a/src/main/java/hudson/plugins/emailext/ExtendedEmailPublisher.java b/src/main/java/hudson/plugins/emailext/ExtendedEmailPublisher.java index 9e64fb054..25062f72c 100644 --- a/src/main/java/hudson/plugins/emailext/ExtendedEmailPublisher.java +++ b/src/main/java/hudson/plugins/emailext/ExtendedEmailPublisher.java @@ -193,6 +193,9 @@ public class ExtendedEmailPublisher extends Notifier implements MatrixAggregatab */ public boolean disabled = false; + /* If true, will check for throttling limits before sending email */ + public boolean throttlingEnabled = false; + /** * How to theTrigger the email if the project is a matrix project. */ @@ -533,7 +536,8 @@ boolean sendMail(ExtendedEmailPublisherContext context) { } MimeMessage msg = createMail(context, fromAddress, session); debug(context.getListener().getLogger(), "Successfully created MimeMessage"); - if (EmailThrottler.getInstance().isThrottlingLimitExceeded() + if (getDescriptor().isThrottlingEnabled() + && EmailThrottler.getInstance().isThrottlingLimitExceeded() && !context.getTrigger().shouldBypassThrottling()) { context.getListener().getLogger().println("Could not send email. Throttling limit exceeded."); return false; @@ -569,7 +573,9 @@ boolean sendMail(ExtendedEmailPublisherContext context) { try { transport.connect(); transport.sendMessage(msg, allRecipients); - EmailThrottler.getInstance().incrementEmailCount(); + if (getDescriptor().isThrottlingEnabled()) { + EmailThrottler.getInstance().incrementEmailCount(); + } break; } catch (SendFailedException e) { if (e.getNextException() != null diff --git a/src/main/java/hudson/plugins/emailext/ExtendedEmailPublisherDescriptor.java b/src/main/java/hudson/plugins/emailext/ExtendedEmailPublisherDescriptor.java index f732546f9..b6a9d4341 100644 --- a/src/main/java/hudson/plugins/emailext/ExtendedEmailPublisherDescriptor.java +++ b/src/main/java/hudson/plugins/emailext/ExtendedEmailPublisherDescriptor.java @@ -160,6 +160,11 @@ public final class ExtendedEmailPublisherDescriptor extends BuildStepDescriptor< */ private boolean enableAllowUnregistered; + /** + * Enables the email throttling feature + */ + private boolean throttlingEnabled = false; + private transient String smtpHost; private transient String smtpPort; private transient String smtpAuthUsername; @@ -300,6 +305,15 @@ public void setDefaultSuffix(String defaultSuffix) { this.defaultSuffix = Util.fixEmptyAndTrim(defaultSuffix); } + public boolean isThrottlingEnabled() { + return throttlingEnabled; + } + + @DataBoundSetter + public void setThrottlingEnabled(boolean throttlingEnabled) { + this.throttlingEnabled = throttlingEnabled; + } + @Restricted(NoExternalUse.class) Session createSession(MailAccount acc, ExtendedEmailPublisherContext context) { final String SMTP_PORT_PROPERTY = "mail.smtp.port"; diff --git a/src/main/resources/hudson/plugins/emailext/ExtendedEmailPublisher/global.groovy b/src/main/resources/hudson/plugins/emailext/ExtendedEmailPublisher/global.groovy index 9cf8943fc..d04baa309 100644 --- a/src/main/resources/hudson/plugins/emailext/ExtendedEmailPublisher/global.groovy +++ b/src/main/resources/hudson/plugins/emailext/ExtendedEmailPublisher/global.groovy @@ -76,6 +76,9 @@ f.section(title: _("Extended E-mail Notification")) { } } + f.entry(field: "throttlingEnabled", title: _("Enable Throttling"), help: "/plugin/email-ext/help/globalConfig/throttlingEnabled.html") { + f.checkbox() + } f.entry(field: "debugMode", title: _("Enable Debug Mode"), help: "/plugin/email-ext/help/globalConfig/debugMode.html") { f.checkbox() } diff --git a/src/main/webapp/help/globalConfig/throttlingEnabled.html b/src/main/webapp/help/globalConfig/throttlingEnabled.html new file mode 100644 index 000000000..a7a50caaa --- /dev/null +++ b/src/main/webapp/help/globalConfig/throttlingEnabled.html @@ -0,0 +1,5 @@ +
+ Check this to enable email throttling which for less important triggers, + will check the number of messages sent and throttle new messages if too + many have been sent. +
diff --git a/src/test/java/hudson/plugins/emailext/ExtendedEmailPublisherTest.java b/src/test/java/hudson/plugins/emailext/ExtendedEmailPublisherTest.java index 5f97332d1..5d9bf39f3 100644 --- a/src/test/java/hudson/plugins/emailext/ExtendedEmailPublisherTest.java +++ b/src/test/java/hudson/plugins/emailext/ExtendedEmailPublisherTest.java @@ -6,11 +6,7 @@ import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Launcher; @@ -123,6 +119,7 @@ public void setUp() throws Exception { publisher.getDescriptor().setDefaultSuffix(null); publisher.getDescriptor().setEmergencyReroute(null); publisher.getDescriptor().setAllowedDomains(null); + publisher.getDescriptor().setThrottlingEnabled(true); oldAuthorizationStrategy = j.jenkins.getAuthorizationStrategy(); oldSecurityRealm = j.jenkins.getSecurityRealm(); oldAdminAddress = JenkinsLocationConfiguration.get().getAdminAddress(); @@ -1702,8 +1699,8 @@ public void testProjectFromWithDefaultSuffix() throws Exception { } @Test - public void testLowerThanLimit() throws Exception { - FreeStyleProject prj = j.createFreeStyleProject("test"); + public void testThrottlingLowerThanLimit() throws Exception { + FreeStyleProject prj = j.createFreeStyleProject("throttle-test"); prj.getPublishersList().add(publisher); publisher.recipientList = "mickey@disney.com"; @@ -1730,8 +1727,8 @@ public void testLowerThanLimit() throws Exception { } @Test - public void testEqualsLimit() throws Exception { - FreeStyleProject prj = j.createFreeStyleProject("test2"); + public void testThrottlingEqualsLimit() throws Exception { + FreeStyleProject prj = j.createFreeStyleProject("throttle-test2"); prj.getPublishersList().add(publisher); publisher.recipientList = "mickey@disney.com"; @@ -1760,8 +1757,8 @@ public void testEqualsLimit() throws Exception { } @Test - public void testOverLimit() throws Exception { - FreeStyleProject prj = j.createFreeStyleProject("test3"); + public void testThrottlingOverLimit() throws Exception { + FreeStyleProject prj = j.createFreeStyleProject("throttle-test3"); prj.getPublishersList().add(publisher); publisher.recipientList = "mickey@disney.com"; @@ -1789,6 +1786,36 @@ public void testOverLimit() throws Exception { Mailbox.get("mickey@disney.com").size()); } + @Test + public void testThrottlingDisabled() throws Exception { + FreeStyleProject prj = j.createFreeStyleProject("throttle-test4"); + prj.getPublishersList().add(publisher); + publisher.getDescriptor().setThrottlingEnabled(false); + + publisher.recipientList = "mickey@disney.com"; + for (int i = 0; i < 130; i++) { + publisher.configuredTriggers.add(new SuccessTrigger( + recProviders, + "$DEFAULT_RECIPIENTS", + "$DEFAULT_REPLYTO", + "$DEFAULT_SUBJECT", + "$DEFAULT_CONTENT", + "", + 0, + "project")); + } + + for (EmailTrigger trigger : publisher.configuredTriggers) { + trigger.getEmail().addRecipientProvider(new ListRecipientProvider()); + } + + FreeStyleBuild build = prj.scheduleBuild2(0).get(); + j.assertBuildStatusSuccess(build); + + assertNotEquals(EmailThrottler.THROTTLING_LIMIT, 130); + assertEquals(130, Mailbox.get("mickey@disney.com").size()); + } + /** * Similar to {@link SleepBuilder} but only on the first build. (Removing * the builder between builds is tricky since you would have to wait for the