mooli tayer has uploaded a new change for review.

Change subject: tools: implement and use transport.idle().
......................................................................

tools: implement and use transport.idle().

As part of transitioning to more then one Transport,
It is no longer possible to let a transport sleep
and retry for as long as it wants. that might
starve other transports especially in a short
notification interval.

Retrying transports (those that can detect sending failures)
Should implement a queue and attempt to send it on idle.

This patch also fixes a bug where smtp loging is done
only before the first send attempt.

Change-Id: I8c4bafb542d28cb584e0751446d3e327f93e8112
Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=1051492
Signed-off-by: Mooli Tayer <mta...@redhat.com>
---
M 
backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/NotificationService.java
M 
backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/transport/Transport.java
M 
backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/transport/smtp/Smtp.java
M 
backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/utils/NotificationProperties.java
M packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.conf.in
5 files changed, 120 insertions(+), 35 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/72/24472/1

diff --git 
a/backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/NotificationService.java
 
b/backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/NotificationService.java
index 4109c1b..1b41512 100644
--- 
a/backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/NotificationService.java
+++ 
b/backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/NotificationService.java
@@ -1,6 +1,8 @@
 package org.ovirt.engine.core.notifier;
 
 import java.sql.SQLException;
+import java.util.Date;
+import java.util.LinkedList;
 import java.util.List;
 
 import org.apache.commons.lang.StringUtils;
@@ -9,6 +11,7 @@
 import org.ovirt.engine.core.notifier.dao.EventsManager;
 import org.ovirt.engine.core.notifier.filter.AuditLogEvent;
 import org.ovirt.engine.core.notifier.filter.FirstMatchSimpleFilter;
+import org.ovirt.engine.core.notifier.transport.Transport;
 import org.ovirt.engine.core.notifier.transport.smtp.Smtp;
 import org.ovirt.engine.core.notifier.utils.NotificationProperties;
 
@@ -28,7 +31,11 @@
 
     private List<FirstMatchSimpleFilter.FilterEntry> configurationFilters;
 
+    private final List<Transport> transports = new LinkedList<>();
+
     private int failedQueries = 0;
+
+    private long lastIdle = 0;
 
     public NotificationService(NotificationProperties prop) throws 
NotificationServiceException {
         this.prop = prop;
@@ -36,10 +43,16 @@
         this.firstMatchSimpleFilter = new FirstMatchSimpleFilter();
         Smtp smtp = new Smtp(prop);
         smtp.addObserver(this.eventsManager);
+        addTransport(smtp);
         this.firstMatchSimpleFilter.registerTransport(smtp);
         configurationFilters = 
FirstMatchSimpleFilter.parse(prop.getProperty(NotificationProperties.FILTER));
         markOldEventsAsProcessed();
     }
+
+    private void addTransport(Transport transport) {
+            this.firstMatchSimpleFilter.registerTransport(transport);
+            this.transports.add(transport);
+        }
 
     private void markOldEventsAsProcessed() {
         
eventsManager.markOldEventsAsProcessed(prop.getInteger(NotificationProperties.DAYS_TO_SEND_ON_STARTUP));
@@ -50,10 +63,25 @@
      */
     @Override
     public void run() {
+        log.debug("Start event notification service iteration");
+        processEvents();
+        long now = new Date(0).getTime();
+        if (now - lastIdle >= getIdleInterval())
+            for (Transport transport : transports) {
+                log.debug(String.format("Transport %s is idle", 
transport.getName()));
+                transport.idle();
+            }
+        lastIdle = now;
+        log.debug("Finished event notification service iteration");
+    }
+
+    private long getIdleInterval() {
+        return Integer.parseInt(NotificationProperties.IDLE_INTERVAL) * 1000;
+    }
+
+    private void processEvents() {
         try {
             try {
-                log.debug("Start event notification service iteration");
-
                 // Clear filter chain
                 firstMatchSimpleFilter.clearFilterEntries();
 
@@ -84,7 +112,6 @@
                     eventsManager.updateAuditLogEventProcessed(event.getId());
                 }
                 deleteObsoleteHistoryData();
-                log.debug("Finished event notification service iteration");
             } catch (SQLException se) {
                 distributeDbDownEvent();
                 throw se;
@@ -92,6 +119,7 @@
         } catch (Throwable t) {
             log.error(String.format("Failed to run the service."), t);
         }
+
     }
 
     private void deleteObsoleteHistoryData() throws SQLException {
diff --git 
a/backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/transport/Transport.java
 
b/backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/transport/Transport.java
index dae285c..cebc592 100644
--- 
a/backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/transport/Transport.java
+++ 
b/backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/transport/Transport.java
@@ -19,4 +19,9 @@
      *            an address understood by this transport
      */
     void dispatchEvent(Event event, String address);
+
+    /**
+     * Upon an idle call a transport performs background tasks if needed,
+     */
+    void idle();
 }
diff --git 
a/backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/transport/smtp/Smtp.java
 
b/backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/transport/smtp/Smtp.java
index ce4c44b..be7bbf4 100644
--- 
a/backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/transport/smtp/Smtp.java
+++ 
b/backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/transport/smtp/Smtp.java
@@ -2,7 +2,9 @@
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.LinkedList;
 import java.util.Observable;
+import java.util.Queue;
 
 import javax.mail.MessagingException;
 
@@ -16,32 +18,36 @@
 import org.ovirt.engine.core.notifier.utils.NotificationProperties;
 
 /**
- * The class sends e-mails to event subscribers.
- * In order to define a proper mail client, the following properties should be 
provided:
- * <li><code>MAIL_SERVER</code> mail server name
- * <li><code>MAIL_PORT</code> mail server port</li><br>
+ * The class sends e-mails to event subscribers. In order to define a proper 
mail client, the following properties
+ * should be provided: <li><code>MAIL_SERVER</code> mail server name 
<li><code>MAIL_PORT</code> mail server port</li><br>
  * The following properties are optional: <br>
- * <li><code>MAIL_USER</code> user name includes a domain (e.g. 
u...@test.com)</li>
- * <li><code>MAIL_PASSWORD</code> user's password</li>
- * <ul>if failed to obtain or uses "localhost" if 
<code>MAIL_MACHINE_NAME</code> not provided</li>
- * <li><code>MAIL_FROM</code> specifies "from" address in sent message, or 
uses value of property <code>MAIL_USER</code> if not provided</li>
- * <ul><li>"from" address should include a domain, same as 
<code>MAIL_USER</code> property
+ * <li><code>MAIL_USER</code> user name includes a domain (e.g. 
u...@test.com)</li> <li><code>MAIL_PASSWORD</code>
+ * user's password</li>
+ * <ul>
+ * if failed to obtain or uses "localhost" if <code>MAIL_MACHINE_NAME</code> 
not provided</li>
+ * <li><code>MAIL_FROM</code> specifies "from" address in sent message, or 
uses value of property <code>MAIL_USER</code>
+ * if not provided</li>
+ * <ul>
+ * <li>"from" address should include a domain, same as <code>MAIL_USER</code> 
property
  * <li><code>MAIL_REPLY_TO</code> specifies "replyTo" address in outgoing 
message
  */
 public class Smtp extends Observable implements Transport {
 
     private static final Logger log = Logger.getLogger(Smtp.class);
-    public static final int ATTEMPTS = 4;
+    private final Queue<DispatchAttempt> sendQueue = new LinkedList<>();
     private JavaMailSender mailSender;
     private String hostName;
     private boolean isBodyHtml = false;
+    private int maxRetries;
 
     public Smtp(NotificationProperties mailProp) {
         mailSender = new JavaMailSender(mailProp);
         String isBodyHtmlStr = 
mailProp.getProperty(NotificationProperties.HTML_MESSAGE_FORMAT);
+
         if (StringUtils.isNotEmpty(isBodyHtmlStr)) {
             isBodyHtml = Boolean.valueOf(isBodyHtmlStr);
         }
+        maxRetries = mailProp.getInteger("MAIL_RETRIES");
         try {
             hostName = InetAddress.getLocalHost().getHostName();
         } catch (UnknownHostException e) {
@@ -57,6 +63,15 @@
 
     @Override
     public void dispatchEvent(Event event, String address) {
+        sendQueue.add(new DispatchAttempt(event, address));
+    }
+
+    @Override
+    public void idle() {
+        DispatchAttempt dispatchAttempt = sendQueue.remove();
+        Event event = dispatchAttempt.getEvent();
+        String address = dispatchAttempt.getAddress();
+
         // throw an exception if not AuditLogEvent
         AuditLogEvent auditLogEvent;
         auditLogEvent = (AuditLogEvent) event;
@@ -75,33 +90,58 @@
             log.debug(String.format("body:%n [%s]",
                     message.getMessageBody()));
         }
-
         String errorMessage = null;
-        int attempts = 0;
         boolean success = false;
-        while (!success && attempts < ATTEMPTS) {
-            try {
-                mailSender.send(address, message.getMessageSubject(), 
message.getMessageBody());
-                setChanged();
-                notifyObservers(DispatchData.success(event, address, 
EventNotificationMethod.EMAIL));
-                success = true;
-            } catch (MessagingException ex) {
-                errorMessage = ex.getMessage();
-            }
-
-            if (!success) {
-                try {
-                    Thread.sleep(30000);
-                } catch (InterruptedException e) {
-                    log.error("Failed to suspend thread for 30 seconds while 
trying to resend a mail message.", e);
-                }
-                attempts++;
-            }
+        try {
+            mailSender.send(address, message.getMessageSubject(), 
message.getMessageBody());
+            setChanged();
+            notifyObservers(DispatchData.success(event, address, 
EventNotificationMethod.EMAIL));
+            success = true;
+        } catch (MessagingException ex) {
+            errorMessage = ex.getMessage();
         }
+        dispatchAttempt.setAttempts(dispatchAttempt.getAttempts() + 1);
         // Could not send after ATTEMPTS attempts.
         if (!success) {
-            setChanged();
-            notifyObservers(DispatchData.failure(event, address, 
EventNotificationMethod.EMAIL, errorMessage));
+            if (dispatchAttempt.getAttempts() < maxRetries) {
+                sendQueue.add(dispatchAttempt);
+            } else { // fail
+                setChanged();
+                notifyObservers(DispatchData.failure(event, address, 
EventNotificationMethod.EMAIL, errorMessage));
+            }
+
+        }
+
+    }
+
+    private class DispatchAttempt {
+
+        private final Event event;
+
+        private final String address;
+
+        private int attempts;
+
+        private DispatchAttempt(Event event, String address) {
+            this.event = event;
+            this.address = address;
+            this.attempts = 0;
+        }
+
+        public Event getEvent() {
+            return event;
+        }
+
+        public String getAddress() {
+            return address;
+        }
+
+        public int getAttempts() {
+            return attempts;
+        }
+
+        public void setAttempts(int attempts) {
+            this.attempts = attempts;
         }
     }
 }
diff --git 
a/backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/utils/NotificationProperties.java
 
b/backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/utils/NotificationProperties.java
index 2ec89f7..a714bcd 100644
--- 
a/backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/utils/NotificationProperties.java
+++ 
b/backend/manager/tools/src/main/java/org/ovirt/engine/core/notifier/utils/NotificationProperties.java
@@ -26,6 +26,13 @@
     public static final String SSL_IGNORE_HOST_VERIFICATION = 
"SSL_IGNORE_HOST_VERIFICATION";
 
     /**
+     * Wait at least IDLE_INTERVAL seconds before allowing a Transport to 
become idle.
+     * An idle transport preforms background tasks like sending unsent queue.
+     */
+    public static final String IDLE_INTERVAL = "IDLE_INTERVAL";
+
+
+    /**
      * Comma separated list of recipients to be informed in case the 
notification service cannot connect to the DB. can
      * be empty.
      */
@@ -76,6 +83,8 @@
      */
     public static final String MAIL_SMTP_ENCRYPTION_TLS = "tls";
 
+    public static final String MAIL_RETRIES = "MAIL_RETRIES";
+
     private static final String GENERIC_MESSAGE = "Check configuration file, ";
 
     // Default files for defaults and overridden values:
diff --git 
a/packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.conf.in 
b/packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.conf.in
index 8f3f3eb..f619eb3 100644
--- a/packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.conf.in
+++ b/packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.conf.in
@@ -112,6 +112,9 @@
 # Specifies 'reply-to' address on sent mail in RFC822 format.
 MAIL_REPLY_TO=
 
+# try before marking message as failed
+MAIL_RETRIES=3
+
 # This parameter specifies how many days of old events are processed and sent
 # when the notifier starts. If set to 2, for example, the notifier will
 # process and send the events of the last two days, older events will just


-- 
To view, visit http://gerrit.ovirt.org/24472
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I8c4bafb542d28cb584e0751446d3e327f93e8112
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: master
Gerrit-Owner: mooli tayer <mta...@redhat.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to