killbill-memoizeit

Refactor overdue code and introduce a new notificationQ to

10/11/2013 8:07:54 PM

Changes

Details

diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/MockOverdueService.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/MockOverdueService.java
index 7c80467..caf6d33 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/MockOverdueService.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/MockOverdueService.java
@@ -16,10 +16,13 @@
 
 package com.ning.billing.beatrix.integration.overdue;
 
+import javax.inject.Named;
+
 import com.google.inject.Inject;
-import com.ning.billing.ovedue.notification.OverdueCheckNotifier;
+import com.ning.billing.ovedue.notification.OverdueNotifier;
 import com.ning.billing.overdue.OverdueProperties;
 import com.ning.billing.overdue.OverdueUserApi;
+import com.ning.billing.overdue.glue.DefaultOverdueModule;
 import com.ning.billing.overdue.listener.OverdueListener;
 import com.ning.billing.overdue.service.DefaultOverdueService;
 import com.ning.billing.overdue.wrapper.OverdueWrapperFactory;
@@ -27,9 +30,11 @@ import com.ning.billing.util.svcsapi.bus.BusService;
 
 public class MockOverdueService extends DefaultOverdueService {
     @Inject
-    public MockOverdueService(final OverdueUserApi userApi, final OverdueProperties properties, final OverdueCheckNotifier notifier,
+    public MockOverdueService(final OverdueUserApi userApi, final OverdueProperties properties,
+                              @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_CHECK_NAMED) final OverdueNotifier checkNotifier,
+                              @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_ASYNC_BUS_NAMED) final OverdueNotifier asyncNotifier,
                               final BusService busService, final OverdueListener listener, final OverdueWrapperFactory factory) {
-        super(userApi, properties, notifier, busService, listener, factory);
+        super(userApi, properties, checkNotifier, asyncNotifier, busService, listener, factory);
     }
 
     public synchronized void loadConfig() throws ServiceException {
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueAsyncBusNotificationKey.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueAsyncBusNotificationKey.java
new file mode 100644
index 0000000..f834ba2
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueAsyncBusNotificationKey.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you 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.ning.billing.ovedue.notification;
+
+import java.util.UUID;
+
+import com.ning.billing.notificationq.api.NotificationEvent;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class OverdueAsyncBusNotificationKey extends OverdueCheckNotificationKey implements NotificationEvent {
+
+    private final OverdueAsyncBusNotificationAction action;
+
+    public enum OverdueAsyncBusNotificationAction {
+        REFRESH,
+        CLEAR
+    }
+
+    @JsonCreator
+    public OverdueAsyncBusNotificationKey(@JsonProperty("uuidKey") final UUID uuidKey,
+                                          @JsonProperty("action") final OverdueAsyncBusNotificationAction action) {
+        super(uuidKey);
+        this.action = action;
+    }
+
+
+    public OverdueAsyncBusNotificationAction getAction() {
+        return action;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof OverdueAsyncBusNotificationKey)) {
+            return false;
+        }
+
+        final OverdueAsyncBusNotificationKey that = (OverdueAsyncBusNotificationKey) o;
+
+        if (action != that.action) {
+            return false;
+        }
+        if (getUuidKey() != null ? !getUuidKey().equals(that.getUuidKey()) : that.getUuidKey() != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = getUuidKey() != null ? getUuidKey().hashCode() : 0;
+        result = 31 * result + (action != null ? action.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueAsyncBusNotifier.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueAsyncBusNotifier.java
new file mode 100644
index 0000000..c0d67bb
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueAsyncBusNotifier.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you 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.ning.billing.ovedue.notification;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.ning.billing.notificationq.api.NotificationEvent;
+import com.ning.billing.notificationq.api.NotificationQueueService;
+import com.ning.billing.overdue.OverdueProperties;
+import com.ning.billing.overdue.listener.OverdueListener;
+
+import com.google.inject.Inject;
+
+public class OverdueAsyncBusNotifier extends DefaultOverdueNotifierBase implements OverdueNotifier {
+
+    private static final Logger log = LoggerFactory.getLogger(OverdueCheckNotifier.class);
+
+    public static final String OVERDUE_ASYNC_BUS_NOTIFIER_QUEUE = "overdue-async-bus-queue";
+
+
+    @Inject
+    public OverdueAsyncBusNotifier(final NotificationQueueService notificationQueueService, final OverdueProperties config,
+                                   final OverdueListener listener) {
+        super(notificationQueueService, config, listener);
+    }
+
+    @Override
+    public Logger getLogger() {
+        return log;
+    }
+
+    @Override
+    public String getQueueName() {
+        return OVERDUE_ASYNC_BUS_NOTIFIER_QUEUE;
+    }
+
+    @Override
+    public void handleReadyNotification(final NotificationEvent notificationKey, final DateTime eventDate, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
+        try {
+            if (!(notificationKey instanceof OverdueAsyncBusNotificationKey)) {
+                getLogger().error("Overdue service received Unexpected notificationKey {}", notificationKey.getClass().getName());
+                return;
+            }
+
+            final OverdueAsyncBusNotificationKey key = (OverdueAsyncBusNotificationKey) notificationKey;
+            switch (key.getAction()) {
+                case CLEAR:
+                    listener.handleClearOverdueForAccount(key.getUuidKey(), userToken, accountRecordId, tenantRecordId);
+                    break;
+                case REFRESH:
+                    listener.handleProcessOverdueForAccount(key.getUuidKey(), userToken, accountRecordId, tenantRecordId);
+                    break;
+                default:
+                    throw new RuntimeException("Unexpected action " + key.getAction() + " for account " + key.getUuidKey());
+            }
+        } catch (IllegalArgumentException e) {
+            log.error("The key returned from the queue " + OVERDUE_ASYNC_BUS_NOTIFIER_QUEUE + " does not contain a valid UUID", e);
+        }
+    }
+
+}
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueAsyncBusPoster.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueAsyncBusPoster.java
new file mode 100644
index 0000000..666e928
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueAsyncBusPoster.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you 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.ning.billing.ovedue.notification;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.joda.time.DateTime;
+import org.skife.jdbi.v2.IDBI;
+
+import com.ning.billing.clock.Clock;
+import com.ning.billing.notificationq.api.NotificationEventWithMetadata;
+import com.ning.billing.notificationq.api.NotificationQueue;
+import com.ning.billing.notificationq.api.NotificationQueueService;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
+import com.ning.billing.util.dao.NonEntityDao;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
+import com.ning.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
+
+import com.google.inject.Inject;
+
+public class OverdueAsyncBusPoster extends DefaultOverduePosterBase {
+
+    @Inject
+    public OverdueAsyncBusPoster(final NotificationQueueService notificationQueueService,
+                                 final IDBI dbi, final Clock clock,
+                                 final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
+        super(notificationQueueService, dbi, clock, cacheControllerDispatcher, nonEntityDao);
+    }
+
+    @Override
+    protected <T extends OverdueCheckNotificationKey> boolean cleanupFutureNotificationsFormTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory,
+                                                                                                        final Collection<NotificationEventWithMetadata<T>> futureNotifications,
+                                                                                                        final DateTime futureNotificationTime,
+                                                                                                        final NotificationQueue overdueQueue) {
+        // If we already have notification for that account we don't insert the new one
+        // Note that this is slightly incorrect because we could for instance already have a REFRESH and insert a CLEAR, but if that were the case,
+        // if means overdue state would change very rapidly and the behavior would anyway be non deterministic
+        //
+        return futureNotifications.size() == 0;
+    }
+
+}
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckNotifier.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckNotifier.java
index fb39124..205142b 100644
--- a/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckNotifier.java
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckNotifier.java
@@ -16,13 +16,54 @@
 
 package com.ning.billing.ovedue.notification;
 
+import java.util.UUID;
 
-public interface OverdueCheckNotifier {
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-    public void initialize();
+import com.ning.billing.notificationq.api.NotificationEvent;
+import com.ning.billing.notificationq.api.NotificationQueueService;
+import com.ning.billing.overdue.OverdueProperties;
+import com.ning.billing.overdue.listener.OverdueListener;
 
-    public void start();
+import com.google.inject.Inject;
 
-    public void stop();
+public class OverdueCheckNotifier extends DefaultOverdueNotifierBase implements OverdueNotifier {
 
+    private static final Logger log = LoggerFactory.getLogger(OverdueCheckNotifier.class);
+
+    public static final String OVERDUE_CHECK_NOTIFIER_QUEUE = "overdue-check-queue";
+
+
+    @Inject
+    public OverdueCheckNotifier(final NotificationQueueService notificationQueueService, final OverdueProperties config,
+                                final OverdueListener listener) {
+        super(notificationQueueService, config, listener);
+    }
+
+    @Override
+    public Logger getLogger() {
+        return log;
+    }
+
+    @Override
+    public String getQueueName() {
+        return OVERDUE_CHECK_NOTIFIER_QUEUE;
+    }
+
+    @Override
+    public void handleReadyNotification(final NotificationEvent notificationKey, final DateTime eventDate, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
+        try {
+            if (!(notificationKey instanceof OverdueCheckNotificationKey)) {
+                getLogger().error("Overdue service received Unexpected notificationKey {}", notificationKey.getClass().getName());
+                return;
+            }
+
+            final OverdueCheckNotificationKey key = (OverdueCheckNotificationKey) notificationKey;
+            listener.handleProcessOverdueForAccount(key.getUuidKey(), userToken, accountRecordId, tenantRecordId);
+        } catch (IllegalArgumentException e) {
+            log.error("The key returned from the NextBillingNotificationQueue is not a valid UUID", e);
+        }
+    }
 }
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckPoster.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckPoster.java
index dbd1a0a..2348711 100644
--- a/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckPoster.java
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckPoster.java
@@ -16,14 +16,63 @@
 
 package com.ning.billing.ovedue.notification;
 
+import java.util.Collection;
+import java.util.Iterator;
+
 import org.joda.time.DateTime;
+import org.skife.jdbi.v2.IDBI;
+
+import com.ning.billing.clock.Clock;
+import com.ning.billing.notificationq.api.NotificationEventWithMetadata;
+import com.ning.billing.notificationq.api.NotificationQueue;
+import com.ning.billing.notificationq.api.NotificationQueueService;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
+import com.ning.billing.util.dao.NonEntityDao;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
+import com.ning.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
+
+import com.google.inject.Inject;
+
+public class OverdueCheckPoster extends DefaultOverduePosterBase {
+
+    @Inject
+    public OverdueCheckPoster(final NotificationQueueService notificationQueueService,
+                                    final IDBI dbi, final Clock clock,
+                                    final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
+        super(notificationQueueService, dbi, clock, cacheControllerDispatcher, nonEntityDao);
+    }
+
+    @Override
+    protected <T extends OverdueCheckNotificationKey> boolean cleanupFutureNotificationsFormTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory,
+                                                                                                        final Collection<NotificationEventWithMetadata<T>> futureNotifications,
+                                                                                                        final DateTime futureNotificationTime, final NotificationQueue overdueQueue) {
 
-import com.ning.billing.account.api.Account;
-import com.ning.billing.callcontext.InternalCallContext;
+        boolean shouldInsertNewNotification = true;
+        if (futureNotifications.size() > 0) {
+            // Results are ordered by effective date asc
+            final DateTime earliestExistingNotificationDate = futureNotifications.iterator().next().getEffectiveDate();
 
-public interface OverdueCheckPoster {
+            final int minIndexToDeleteFrom;
+            if (earliestExistingNotificationDate.isBefore(futureNotificationTime)) {
+                // We don't have to insert a new one. For sanity, delete any other future notification
+                minIndexToDeleteFrom = 1;
+                shouldInsertNewNotification = false;
+            } else {
+                // We win - we are before any other already recorded. Delete all others.
+                minIndexToDeleteFrom = 0;
+            }
 
-    void insertOverdueCheckNotification(Account blockable, DateTime futureNotificationTime, final InternalCallContext context);
+            int index = 0;
+            final Iterator<NotificationEventWithMetadata<T>> it = futureNotifications.iterator();
+            while (it.hasNext()) {
+                final NotificationEventWithMetadata<T> cur = it.next();
+                if (minIndexToDeleteFrom <= index) {
+                    overdueQueue.removeNotificationFromTransaction(entitySqlDaoWrapperFactory.getSqlDao(), cur.getRecordId());
+                }
+                index++;
+            }
+        }
+        return shouldInsertNewNotification;
+    }
 
-    void clearNotificationsFor(Account blockable, final InternalCallContext context);
 }
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueNotifier.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueNotifier.java
new file mode 100644
index 0000000..b94f40d
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueNotifier.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you 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.ning.billing.ovedue.notification;
+
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.notificationq.api.NotificationEvent;
+
+public interface OverdueNotifier {
+
+    public void initialize();
+
+    public void start();
+
+    public void stop();
+
+    public abstract void handleReadyNotification(final NotificationEvent notificationKey, final DateTime eventDate, final UUID userToken, final Long accountRecordId, final Long tenantRecordId);
+
+}
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/OverduePoster.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverduePoster.java
new file mode 100644
index 0000000..bc5442e
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverduePoster.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you 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.ning.billing.ovedue.notification;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.callcontext.InternalCallContext;
+import com.ning.billing.notificationq.api.NotificationQueue;
+
+public interface OverduePoster {
+
+    public  <T extends OverdueCheckNotificationKey> void insertOverdueNotification(final UUID accountId, final DateTime futureNotificationTime, final String overdueQueueName, final T notificationKey, final InternalCallContext context);
+
+    public  <T extends OverdueCheckNotificationKey> void clearOverdueCheckNotifications(UUID accountId, final String overdueQueueName, final Class<T> clazz, final InternalCallContext context);
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
index 04af8f9..0859297 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
@@ -21,6 +21,8 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
 
+import javax.inject.Named;
+
 import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
 import org.joda.time.Period;
@@ -47,7 +49,9 @@ import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoiceInternalApi;
 import com.ning.billing.junction.BlockingInternalApi;
 import com.ning.billing.junction.DefaultBlockingState;
-import com.ning.billing.ovedue.notification.OverdueCheckPoster;
+import com.ning.billing.ovedue.notification.OverdueCheckNotificationKey;
+import com.ning.billing.ovedue.notification.OverdueCheckNotifier;
+import com.ning.billing.ovedue.notification.OverduePoster;
 import com.ning.billing.overdue.OverdueApiException;
 import com.ning.billing.overdue.OverdueCancellationPolicy;
 import com.ning.billing.overdue.OverdueService;
@@ -55,6 +59,7 @@ import com.ning.billing.overdue.OverdueState;
 import com.ning.billing.overdue.config.api.BillingState;
 import com.ning.billing.overdue.config.api.OverdueException;
 import com.ning.billing.overdue.config.api.OverdueStateSet;
+import com.ning.billing.overdue.glue.DefaultOverdueModule;
 import com.ning.billing.tag.TagInternalApi;
 import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.email.DefaultEmailSender;
@@ -74,7 +79,7 @@ public class OverdueStateApplicator {
 
     private final BlockingInternalApi blockingApi;
     private final Clock clock;
-    private final OverdueCheckPoster poster;
+    private final OverduePoster checkPoster;
     private final PersistentBus bus;
     private final AccountInternalApi accountApi;
     private final EntitlementApi entitlementApi;
@@ -90,7 +95,7 @@ public class OverdueStateApplicator {
                                   final EntitlementApi entitlementApi,
                                   final InvoiceInternalApi invoiceInternalApi,
                                   final Clock clock,
-                                  final OverdueCheckPoster poster,
+                                  @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_CHECK_NAMED)final OverduePoster checkPoster,
                                   final OverdueEmailGenerator overdueEmailGenerator,
                                   final EmailConfig config,
                                   final PersistentBus bus,
@@ -102,7 +107,7 @@ public class OverdueStateApplicator {
         this.entitlementApi = entitlementApi;
         this.invoiceInternalApi = invoiceInternalApi;
         this.clock = clock;
-        this.poster = poster;
+        this.checkPoster = checkPoster;
         this.overdueEmailGenerator = overdueEmailGenerator;
         this.tagApi = tagApi;
         this.nonEntityDao = nonEntityDao;
@@ -243,13 +248,14 @@ public class OverdueStateApplicator {
         return nextOverdueState.disableEntitlementAndChangesBlocked();
     }
 
-    protected void createFutureNotification(final Account overdueable, final DateTime timeOfNextCheck, final InternalCallContext context) {
-        poster.insertOverdueCheckNotification(overdueable, timeOfNextCheck, context);
+    protected void createFutureNotification(final Account account, final DateTime timeOfNextCheck, final InternalCallContext context) {
+        final OverdueCheckNotificationKey notificationKey = new OverdueCheckNotificationKey(account.getId());
+        checkPoster.insertOverdueNotification(account.getId(), timeOfNextCheck, OverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE, notificationKey, context);
     }
 
-    protected void clearFutureNotification(final Account blockable, final InternalCallContext context) {
+    protected void clearFutureNotification(final Account account, final InternalCallContext context) {
         // Need to clear the override table here too (when we add it)
-        poster.clearNotificationsFor(blockable, context);
+        checkPoster.clearOverdueCheckNotifications(account.getId(), OverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE, OverdueCheckNotificationKey.class, context);
     }
 
     private void cancelSubscriptionsIfRequired(final Account account, final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueException {
diff --git a/overdue/src/main/java/com/ning/billing/overdue/glue/DefaultOverdueModule.java b/overdue/src/main/java/com/ning/billing/overdue/glue/DefaultOverdueModule.java
index 06e9e98..0fca842 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/glue/DefaultOverdueModule.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/glue/DefaultOverdueModule.java
@@ -20,10 +20,13 @@ import org.skife.config.ConfigSource;
 import org.skife.config.ConfigurationObjectFactory;
 
 import com.ning.billing.glue.OverdueModule;
-import com.ning.billing.ovedue.notification.DefaultOverdueCheckNotifier;
-import com.ning.billing.ovedue.notification.DefaultOverdueCheckPoster;
+import com.ning.billing.ovedue.notification.DefaultOverduePosterBase;
+import com.ning.billing.ovedue.notification.OverdueAsyncBusNotifier;
+import com.ning.billing.ovedue.notification.OverdueAsyncBusPoster;
 import com.ning.billing.ovedue.notification.OverdueCheckNotifier;
 import com.ning.billing.ovedue.notification.OverdueCheckPoster;
+import com.ning.billing.ovedue.notification.OverduePoster;
+import com.ning.billing.ovedue.notification.OverdueNotifier;
 import com.ning.billing.overdue.OverdueProperties;
 import com.ning.billing.overdue.OverdueService;
 import com.ning.billing.overdue.OverdueUserApi;
@@ -35,11 +38,15 @@ import com.ning.billing.overdue.service.DefaultOverdueService;
 import com.ning.billing.overdue.wrapper.OverdueWrapperFactory;
 
 import com.google.inject.AbstractModule;
+import com.google.inject.name.Names;
 
 public class DefaultOverdueModule extends AbstractModule implements OverdueModule {
 
     protected final ConfigSource configSource;
 
+    public static final String OVERDUE_NOTIFIER_CHECK_NAMED = "overdueNotifierCheck";
+    public static final String OVERDUE_NOTIFIER_ASYNC_BUS_NAMED = "overdueNotifierAsyncBus";
+
     public DefaultOverdueModule(final ConfigSource configSource) {
         this.configSource = configSource;
     }
@@ -55,9 +62,12 @@ public class DefaultOverdueModule extends AbstractModule implements OverdueModul
 
         final OverdueProperties config = new ConfigurationObjectFactory(configSource).build(OverdueProperties.class);
         bind(OverdueProperties.class).toInstance(config);
-        //bind(ExtendedOverdueService.class).to(DefaultOverdueService.class).asEagerSingleton();
-        bind(OverdueCheckNotifier.class).to(DefaultOverdueCheckNotifier.class).asEagerSingleton();
-        bind(OverdueCheckPoster.class).to(DefaultOverdueCheckPoster.class).asEagerSingleton();
+
+        bind(OverdueNotifier.class).annotatedWith(Names.named(OVERDUE_NOTIFIER_CHECK_NAMED)).to(OverdueCheckNotifier.class).asEagerSingleton();
+        bind(OverdueNotifier.class).annotatedWith(Names.named(OVERDUE_NOTIFIER_ASYNC_BUS_NAMED)).to(OverdueAsyncBusNotifier.class).asEagerSingleton();
+
+        bind(OverduePoster.class).annotatedWith(Names.named(OVERDUE_NOTIFIER_CHECK_NAMED)).to(OverdueCheckPoster.class).asEagerSingleton();
+        bind(OverduePoster.class).annotatedWith(Names.named(OVERDUE_NOTIFIER_ASYNC_BUS_NAMED)).to(OverdueAsyncBusPoster.class).asEagerSingleton();
     }
 
     protected void installOverdueService() {
diff --git a/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueDispatcher.java b/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueDispatcher.java
index 5630c16..c142466 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueDispatcher.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueDispatcher.java
@@ -46,19 +46,19 @@ public class OverdueDispatcher {
         clearOverdue(accountId, context);
     }
 
-    public void processOverdue(final UUID blockableId, final InternalCallContext context) {
+    private void processOverdue(final UUID accountId, final InternalCallContext context) {
         try {
-            factory.createOverdueWrapperFor(blockableId, context).refresh(context);
+            factory.createOverdueWrapperFor(accountId, context).refresh(context);
         } catch (BillingExceptionBase e) {
-            log.error(String.format("Error processing Overdue for blockable %s", blockableId), e);
+            log.error(String.format("Error processing Overdue for blockable %s", accountId), e);
         }
     }
 
-    public void clearOverdue(final UUID blockableId, final InternalCallContext context) {
+    private void clearOverdue(final UUID accountId, final InternalCallContext context) {
         try {
-            factory.createOverdueWrapperFor(blockableId, context).clear(context);
+            factory.createOverdueWrapperFor(accountId, context).clear(context);
         } catch (BillingExceptionBase e) {
-            log.error(String.format("Error processing Overdue for blockable %s (type %s)", blockableId), e);
+            log.error(String.format("Error processing Overdue for blockable %s (type %s)", accountId), e);
         }
     }
 }
diff --git a/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueListener.java b/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueListener.java
index 4bb873f..bd69aa2 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueListener.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueListener.java
@@ -18,11 +18,20 @@ package com.ning.billing.overdue.listener;
 
 import java.util.UUID;
 
+import javax.inject.Named;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.ning.billing.ObjectType;
+import com.ning.billing.clock.Clock;
+import com.ning.billing.ovedue.notification.OverdueAsyncBusNotificationKey;
+import com.ning.billing.ovedue.notification.OverdueAsyncBusNotificationKey.OverdueAsyncBusNotificationAction;
+import com.ning.billing.ovedue.notification.OverdueAsyncBusNotifier;
 import com.ning.billing.ovedue.notification.OverdueCheckNotificationKey;
+import com.ning.billing.ovedue.notification.OverdueCheckNotifier;
+import com.ning.billing.ovedue.notification.OverduePoster;
+import com.ning.billing.overdue.glue.DefaultOverdueModule;
 import com.ning.billing.util.callcontext.CallOrigin;
 import com.ning.billing.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
@@ -41,13 +50,19 @@ public class OverdueListener {
 
     private final OverdueDispatcher dispatcher;
     private final InternalCallContextFactory internalCallContextFactory;
+    private final OverduePoster asyncPoster;
+    private final Clock clock;
 
     private static final Logger log = LoggerFactory.getLogger(OverdueListener.class);
 
     @Inject
     public OverdueListener(final OverdueDispatcher dispatcher,
+                           final Clock clock,
+                           @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_ASYNC_BUS_NAMED)final OverduePoster asyncPoster,
                            final InternalCallContextFactory internalCallContextFactory) {
         this.dispatcher = dispatcher;
+        this.asyncPoster = asyncPoster;
+        this.clock = clock;
         this.internalCallContextFactory = internalCallContextFactory;
     }
 
@@ -55,7 +70,8 @@ public class OverdueListener {
     public void handle_OVERDUE_ENFORCEMENT_OFF_Insert(final ControlTagCreationInternalEvent event) {
         if (event.getTagDefinition().getName().equals(ControlTagType.OVERDUE_ENFORCEMENT_OFF.toString()) && event.getObjectType() == ObjectType.ACCOUNT) {
             final UUID accountId = event.getObjectId();
-            dispatcher.clearOverdueForAccount(accountId, createCallContext(event.getUserToken(), event.getSearchKey1(), event.getSearchKey2()));
+            final OverdueAsyncBusNotificationKey notificationKey = new OverdueAsyncBusNotificationKey(accountId, OverdueAsyncBusNotificationAction.CLEAR);
+            asyncPoster.insertOverdueNotification(accountId, clock.getUTCNow(), OverdueAsyncBusNotifier.OVERDUE_ASYNC_BUS_NOTIFIER_QUEUE, notificationKey, createCallContext(event.getUserToken(), event.getSearchKey1(), event.getSearchKey2()));
         }
     }
 
@@ -63,38 +79,41 @@ public class OverdueListener {
     public void handle_OVERDUE_ENFORCEMENT_OFF_Removal(final ControlTagDeletionInternalEvent event) {
         if (event.getTagDefinition().getName().equals(ControlTagType.OVERDUE_ENFORCEMENT_OFF.toString()) && event.getObjectType() == ObjectType.ACCOUNT) {
             final UUID accountId = event.getObjectId();
-            dispatcher.processOverdueForAccount(accountId, createCallContext(event.getUserToken(), event.getSearchKey1(), event.getSearchKey2()));
+            final OverdueAsyncBusNotificationKey notificationKey = new OverdueAsyncBusNotificationKey(accountId, OverdueAsyncBusNotificationAction.REFRESH);
+            asyncPoster.insertOverdueNotification(accountId, clock.getUTCNow(), OverdueAsyncBusNotifier.OVERDUE_ASYNC_BUS_NOTIFIER_QUEUE, notificationKey, createCallContext(event.getUserToken(), event.getSearchKey1(), event.getSearchKey2()));
         }
     }
 
 
     @Subscribe
     public void handlePaymentInfoEvent(final PaymentInfoInternalEvent event) {
-
         log.debug("Received PaymentInfo event {}", event);
-        dispatcher.processOverdueForAccount(event.getAccountId(), createCallContext(event.getUserToken(), event.getSearchKey1(), event.getSearchKey2()));
+        final OverdueAsyncBusNotificationKey notificationKey = new OverdueAsyncBusNotificationKey(event.getAccountId(), OverdueAsyncBusNotificationAction.REFRESH);
+        asyncPoster.insertOverdueNotification(event.getAccountId(), clock.getUTCNow(), OverdueAsyncBusNotifier.OVERDUE_ASYNC_BUS_NOTIFIER_QUEUE, notificationKey, createCallContext(event.getUserToken(), event.getSearchKey1(), event.getSearchKey2()));
     }
 
     @Subscribe
     public void handlePaymentErrorEvent(final PaymentErrorInternalEvent event) {
-
         log.debug("Received PaymentError event {}", event);
-        final UUID accountId = event.getAccountId();
-        dispatcher.processOverdueForAccount(accountId, createCallContext(event.getUserToken(), event.getSearchKey1(), event.getSearchKey2()));
+        final OverdueAsyncBusNotificationKey notificationKey = new OverdueAsyncBusNotificationKey(event.getAccountId(), OverdueAsyncBusNotificationAction.REFRESH);
+        asyncPoster.insertOverdueNotification(event.getAccountId(), clock.getUTCNow(), OverdueAsyncBusNotifier.OVERDUE_ASYNC_BUS_NOTIFIER_QUEUE, notificationKey, createCallContext(event.getUserToken(), event.getSearchKey1(), event.getSearchKey2()));
     }
 
     @Subscribe
     public void handleInvoiceAdjustmentEvent(final InvoiceAdjustmentInternalEvent event) {
-
         log.debug("Received InvoiceAdjustment event {}", event);
-        final UUID accountId = event.getAccountId();
-        dispatcher.processOverdueForAccount(accountId, createCallContext(event.getUserToken(), event.getSearchKey1(), event.getSearchKey2()));
+        final OverdueAsyncBusNotificationKey notificationKey = new OverdueAsyncBusNotificationKey(event.getAccountId(), OverdueAsyncBusNotificationAction.REFRESH);
+        asyncPoster.insertOverdueNotification(event.getAccountId(), clock.getUTCNow(), OverdueAsyncBusNotifier.OVERDUE_ASYNC_BUS_NOTIFIER_QUEUE, notificationKey, createCallContext(event.getUserToken(), event.getSearchKey1(), event.getSearchKey2()));
+    }
+
+    public void handleProcessOverdueForAccount(final UUID accountId, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
+        log.info(String.format("Handle overdue notification processing for id = %s", accountId));
+        dispatcher.processOverdueForAccount(accountId, createCallContext(userToken, accountRecordId, tenantRecordId));
     }
 
-    public void handleNextOverdueCheck(final OverdueCheckNotificationKey notificationKey, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
-        log.info(String.format("Received OD checkup notification for id = %s",
-                               notificationKey.getUuidKey()));
-        dispatcher.processOverdue(notificationKey.getUuidKey(), createCallContext(userToken, accountRecordId, tenantRecordId));
+    public void handleClearOverdueForAccount(final UUID accountId, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
+        log.info(String.format("Handle overdue notification clear for id = %s", accountId));
+        dispatcher.clearOverdueForAccount(accountId, createCallContext(userToken, accountRecordId, tenantRecordId));
     }
 
     private InternalCallContext createCallContext(final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
diff --git a/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java b/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java
index 1be6b2e..4194687 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java
@@ -19,18 +19,21 @@ package com.ning.billing.overdue.service;
 import java.net.URI;
 import java.net.URISyntaxException;
 
+import javax.inject.Named;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.ning.billing.bus.api.PersistentBus.EventBusException;
 import com.ning.billing.lifecycle.LifecycleHandlerType;
 import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel;
-import com.ning.billing.ovedue.notification.OverdueCheckNotifier;
+import com.ning.billing.ovedue.notification.OverdueNotifier;
 import com.ning.billing.overdue.OverdueProperties;
 import com.ning.billing.overdue.OverdueService;
 import com.ning.billing.overdue.OverdueUserApi;
 import com.ning.billing.overdue.api.DefaultOverdueUserApi;
 import com.ning.billing.overdue.config.OverdueConfig;
+import com.ning.billing.overdue.glue.DefaultOverdueModule;
 import com.ning.billing.overdue.listener.OverdueListener;
 import com.ning.billing.overdue.wrapper.OverdueWrapperFactory;
 import com.ning.billing.util.config.catalog.XMLLoader;
@@ -43,9 +46,11 @@ public class DefaultOverdueService implements OverdueService {
     private static final Logger log = LoggerFactory.getLogger(DefaultOverdueService.class);
 
     public static final String OVERDUE_SERVICE_NAME = "overdue-service";
+
     private final OverdueUserApi userApi;
     private final OverdueProperties properties;
-    private final OverdueCheckNotifier notifier;
+    private final OverdueNotifier asyncNotifier;
+    private final OverdueNotifier checkNotifier;
     private final BusService busService;
     private final OverdueListener listener;
     private final OverdueWrapperFactory factory;
@@ -57,13 +62,15 @@ public class DefaultOverdueService implements OverdueService {
     public DefaultOverdueService(
             final OverdueUserApi userApi,
             final OverdueProperties properties,
-            final OverdueCheckNotifier notifier,
+            @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_CHECK_NAMED) final OverdueNotifier checkNotifier,
+            @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_ASYNC_BUS_NAMED) final OverdueNotifier asyncNotifier,
             final BusService busService,
             final OverdueListener listener,
             final OverdueWrapperFactory factory) {
         this.userApi = userApi;
         this.properties = properties;
-        this.notifier = notifier;
+        this.checkNotifier = checkNotifier;
+        this.asyncNotifier = asyncNotifier;
         this.busService = busService;
         this.listener = listener;
         this.factory = factory;
@@ -80,11 +87,6 @@ public class DefaultOverdueService implements OverdueService {
         return userApi;
     }
 
-    //@Override
-    public OverdueConfig getOverdueConfig() {
-        return overdueConfig;
-    }
-
     @LifecycleHandlerType(LifecycleLevel.LOAD_CATALOG)
     public synchronized void loadConfig() throws ServiceException {
         if (!isConfigLoaded) {
@@ -114,7 +116,8 @@ public class DefaultOverdueService implements OverdueService {
     @LifecycleHandlerType(LifecycleHandlerType.LifecycleLevel.INIT_SERVICE)
     public void initialize() {
         registerForBus();
-        notifier.initialize();
+        checkNotifier.initialize();
+        asyncNotifier.initialize();
     }
 
     private void registerForBus() {
@@ -127,7 +130,8 @@ public class DefaultOverdueService implements OverdueService {
 
     @LifecycleHandlerType(LifecycleLevel.START_SERVICE)
     public void start() {
-        notifier.start();
+        checkNotifier.start();
+        asyncNotifier.start();
     }
 
     @LifecycleHandlerType(LifecycleLevel.STOP_SERVICE)
@@ -137,6 +141,7 @@ public class DefaultOverdueService implements OverdueService {
         } catch (final EventBusException e) {
             log.error("Problem encountered registering OverdueListener on the Event Bus", e);
         }
-        notifier.stop();
+        checkNotifier.stop();
+        asyncNotifier.stop();
     }
 }
diff --git a/overdue/src/test/java/com/ning/billing/ovedue/notification/TestDefaultOverdueCheckPoster.java b/overdue/src/test/java/com/ning/billing/ovedue/notification/TestDefaultOverdueCheckPoster.java
index e44cd73..50b8459 100644
--- a/overdue/src/test/java/com/ning/billing/ovedue/notification/TestDefaultOverdueCheckPoster.java
+++ b/overdue/src/test/java/com/ning/billing/ovedue/notification/TestDefaultOverdueCheckPoster.java
@@ -27,13 +27,10 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import com.ning.billing.account.api.Account;
-import com.ning.billing.entitlement.api.Blockable;
 import com.ning.billing.notificationq.api.NotificationEventWithMetadata;
 import com.ning.billing.notificationq.api.NotificationQueue;
 import com.ning.billing.overdue.OverdueTestSuiteWithEmbeddedDB;
 import com.ning.billing.overdue.service.DefaultOverdueService;
-import com.ning.billing.subscription.api.SubscriptionBase;
-import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionalJdbiWrapper;
@@ -55,7 +52,7 @@ public class TestDefaultOverdueCheckPoster extends OverdueTestSuiteWithEmbeddedD
         entitySqlDaoTransactionalJdbiWrapper = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao);
 
         overdueQueue = notificationQueueService.getNotificationQueue(DefaultOverdueService.OVERDUE_SERVICE_NAME,
-                                                                     DefaultOverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE);
+                                                                     OverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE);
         Assert.assertTrue(overdueQueue.isStarted());
 
         testReferenceTime = clock.getUTCNow();
@@ -71,36 +68,28 @@ public class TestDefaultOverdueCheckPoster extends OverdueTestSuiteWithEmbeddedD
         insertOverdueCheckAndVerifyQueueContent(overdueable, 5, 5);
         insertOverdueCheckAndVerifyQueueContent(overdueable, 15, 5);
 
-        // Check we don't conflict with other overdueables
-        final UUID bundleId = UUID.randomUUID();
-        final Account otherOverdueable = Mockito.mock(Account.class);
-        Mockito.when(otherOverdueable.getId()).thenReturn(bundleId);
-
-        insertOverdueCheckAndVerifyQueueContent(otherOverdueable, 10, 10);
-        insertOverdueCheckAndVerifyQueueContent(otherOverdueable, 5, 5);
-        insertOverdueCheckAndVerifyQueueContent(otherOverdueable, 15, 5);
-
         // Verify the final content of the queue
-        Assert.assertEquals(overdueQueue.getFutureNotificationForSearchKey1(OverdueCheckNotificationKey.class, internalCallContext.getAccountRecordId()).size(), 2);
+        Assert.assertEquals(overdueQueue.getFutureNotificationForSearchKey1(OverdueCheckNotificationKey.class, internalCallContext.getAccountRecordId()).size(), 1);
     }
 
-    private void insertOverdueCheckAndVerifyQueueContent(final Account overdueable, final int nbDaysInFuture, final int expectedNbDaysInFuture) throws IOException {
+    private void insertOverdueCheckAndVerifyQueueContent(final Account account, final int nbDaysInFuture, final int expectedNbDaysInFuture) throws IOException {
         final DateTime futureNotificationTime = testReferenceTime.plusDays(nbDaysInFuture);
-        poster.insertOverdueCheckNotification(overdueable, futureNotificationTime, internalCallContext);
 
-        final OverdueCheckNotificationKey notificationKey = new OverdueCheckNotificationKey(overdueable.getId());
-        final Collection<NotificationEventWithMetadata<OverdueCheckNotificationKey>> notificationsForKey = getNotificationsForOverdueable(overdueable);
+        final OverdueCheckNotificationKey notificationKey = new OverdueCheckNotificationKey(account.getId());
+        checkPoster.insertOverdueNotification(account.getId(), futureNotificationTime, OverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE, notificationKey, internalCallContext);
+
+        final Collection<NotificationEventWithMetadata<OverdueCheckNotificationKey>> notificationsForKey = getNotificationsForOverdueable(account);
         Assert.assertEquals(notificationsForKey.size(), 1);
         final NotificationEventWithMetadata nm = notificationsForKey.iterator().next();
         Assert.assertEquals(nm.getEvent(), notificationKey);
         Assert.assertEquals(nm.getEffectiveDate(), testReferenceTime.plusDays(expectedNbDaysInFuture));
     }
 
-    private Collection<NotificationEventWithMetadata<OverdueCheckNotificationKey>> getNotificationsForOverdueable(final Account overdueable) {
+    private Collection<NotificationEventWithMetadata<OverdueCheckNotificationKey>> getNotificationsForOverdueable(final Account account) {
         return entitySqlDaoTransactionalJdbiWrapper.execute(new EntitySqlDaoTransactionWrapper<Collection<NotificationEventWithMetadata<OverdueCheckNotificationKey>>>() {
             @Override
             public Collection<NotificationEventWithMetadata<OverdueCheckNotificationKey>> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
-                return ((DefaultOverdueCheckPoster) poster).getFutureNotificationsForAccountAndOverdueableInTransaction(entitySqlDaoWrapperFactory, overdueQueue, overdueable, internalCallContext);
+                return ((OverdueCheckPoster)checkPoster).getFutureNotificationsForAccountInTransaction(entitySqlDaoWrapperFactory, overdueQueue, account.getId(), OverdueCheckNotificationKey.class, internalCallContext);
             }
         });
     }
diff --git a/overdue/src/test/java/com/ning/billing/overdue/notification/TestOverdueCheckNotifier.java b/overdue/src/test/java/com/ning/billing/overdue/notification/TestOverdueCheckNotifier.java
index 48f11b7..cbac52d 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/notification/TestOverdueCheckNotifier.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/notification/TestOverdueCheckNotifier.java
@@ -27,9 +27,9 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import com.ning.billing.account.api.Account;
-import com.ning.billing.ovedue.notification.DefaultOverdueCheckNotifier;
 import com.ning.billing.ovedue.notification.OverdueCheckNotificationKey;
 import com.ning.billing.ovedue.notification.OverdueCheckNotifier;
+import com.ning.billing.ovedue.notification.OverdueNotifier;
 import com.ning.billing.overdue.OverdueTestSuiteWithEmbeddedDB;
 import com.ning.billing.overdue.listener.OverdueListener;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
@@ -41,29 +41,29 @@ import static java.util.concurrent.TimeUnit.SECONDS;
 public class TestOverdueCheckNotifier extends OverdueTestSuiteWithEmbeddedDB {
 
     private OverdueListenerMock mockListener;
-    private OverdueCheckNotifier notifierForMock;
+    private OverdueNotifier notifierForMock;
 
     private static final class OverdueListenerMock extends OverdueListener {
 
         int eventCount = 0;
-        UUID latestSubscriptionId = null;
+        UUID latestAccountId = null;
 
         public OverdueListenerMock(final InternalCallContextFactory internalCallContextFactory) {
-            super(null, internalCallContextFactory);
+            super(null, getClock(), null,internalCallContextFactory);
         }
 
         @Override
-        public void handleNextOverdueCheck(final OverdueCheckNotificationKey key, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
+        public void handleProcessOverdueForAccount(final UUID accountId, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
             eventCount++;
-            latestSubscriptionId = key.getUuidKey();
+            latestAccountId = accountId;
         }
 
         public int getEventCount() {
             return eventCount;
         }
 
-        public UUID getLatestSubscriptionId() {
-            return latestSubscriptionId;
+        public UUID getLatestAccountId() {
+            return latestAccountId;
         }
     }
 
@@ -71,13 +71,13 @@ public class TestOverdueCheckNotifier extends OverdueTestSuiteWithEmbeddedDB {
     @BeforeMethod(groups = "slow")
     public void beforeMethod() throws Exception {
         //super.beforeMethod();
-        // We override the parent method on purpose, because we want to register a different DefaultOverdueCheckNotifier
+        // We override the parent method on purpose, because we want to register a different OverdueCheckNotifier
 
         final Account account = Mockito.mock(Account.class);
         Mockito.when(accountApi.getAccountById(Mockito.<UUID>any(), Mockito.<InternalTenantContext>any())).thenReturn(account);
 
         mockListener = new OverdueListenerMock(internalCallContextFactory);
-        notifierForMock = new DefaultOverdueCheckNotifier(notificationQueueService, overdueProperties, mockListener);
+        notifierForMock = new OverdueCheckNotifier(notificationQueueService, overdueProperties, mockListener);
 
         notifierForMock.initialize();
         notifierForMock.start();
@@ -92,13 +92,14 @@ public class TestOverdueCheckNotifier extends OverdueTestSuiteWithEmbeddedDB {
 
     @Test(groups = "slow")
     public void test() throws Exception {
-        final UUID subscriptionId = new UUID(0L, 1L);
-        final Account blockable = Mockito.mock(Account.class);
-        Mockito.when(blockable.getId()).thenReturn(subscriptionId);
+        final UUID accountId = new UUID(0L, 1L);
+        final Account account = Mockito.mock(Account.class);
+        Mockito.when(account.getId()).thenReturn(accountId);
         final DateTime now = clock.getUTCNow();
         final DateTime readyTime = now.plusMillis(2000);
 
-        poster.insertOverdueCheckNotification(blockable, readyTime, internalCallContext);
+        final OverdueCheckNotificationKey notificationKey = new OverdueCheckNotificationKey(accountId);
+        checkPoster.insertOverdueNotification(accountId, readyTime, OverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE, notificationKey, internalCallContext);
 
         // Move time in the future after the notification effectiveDate
         clock.setDeltaFromReality(3000);
@@ -111,6 +112,6 @@ public class TestOverdueCheckNotifier extends OverdueTestSuiteWithEmbeddedDB {
         });
 
         Assert.assertEquals(mockListener.getEventCount(), 1);
-        Assert.assertEquals(mockListener.getLatestSubscriptionId(), subscriptionId);
+        Assert.assertEquals(mockListener.getLatestAccountId(), accountId);
     }
 }
diff --git a/overdue/src/test/java/com/ning/billing/overdue/OverdueTestSuiteNoDB.java b/overdue/src/test/java/com/ning/billing/overdue/OverdueTestSuiteNoDB.java
index df23920..1d77fc2 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/OverdueTestSuiteNoDB.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/OverdueTestSuiteNoDB.java
@@ -16,18 +16,21 @@
 
 package com.ning.billing.overdue;
 
+import javax.inject.Named;
+
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
 
 import com.ning.billing.GuicyKillbillTestSuiteNoDB;
 import com.ning.billing.bus.api.PersistentBus;
+import com.ning.billing.ovedue.notification.OverduePoster;
 import com.ning.billing.overdue.calculator.BillingStateCalculator;
 import com.ning.billing.notificationq.api.NotificationQueueService;
-import com.ning.billing.ovedue.notification.OverdueCheckNotifier;
-import com.ning.billing.ovedue.notification.OverdueCheckPoster;
+import com.ning.billing.ovedue.notification.OverdueNotifier;
 import com.ning.billing.overdue.applicator.OverdueBusListenerTester;
 import com.ning.billing.overdue.applicator.OverdueStateApplicator;
+import com.ning.billing.overdue.glue.DefaultOverdueModule;
 import com.ning.billing.overdue.glue.TestOverdueModuleNoDB;
 import com.ning.billing.overdue.service.DefaultOverdueService;
 import com.ning.billing.overdue.wrapper.OverdueWrapperFactory;
@@ -63,10 +66,18 @@ public abstract class OverdueTestSuiteNoDB extends GuicyKillbillTestSuiteNoDB {
     protected NotificationQueueService notificationQueueService;
     @Inject
     protected OverdueBusListenerTester listener;
+    @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_CHECK_NAMED)
+    @Inject
+    protected OverdueNotifier checkNotifier;
+    @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_ASYNC_BUS_NAMED)
+    @Inject
+    protected OverdueNotifier asyncNotifier;
     @Inject
-    protected OverdueCheckNotifier notifier;
+    @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_CHECK_NAMED)
+    protected OverduePoster checkPoster;
     @Inject
-    protected OverdueCheckPoster poster;
+    @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_ASYNC_BUS_NAMED)
+    protected OverduePoster asyncPoster;
     @Inject
     protected OverdueStateApplicator applicator;
     @Inject
diff --git a/overdue/src/test/java/com/ning/billing/overdue/OverdueTestSuiteWithEmbeddedDB.java b/overdue/src/test/java/com/ning/billing/overdue/OverdueTestSuiteWithEmbeddedDB.java
index 5ab64ba..af20526 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/OverdueTestSuiteWithEmbeddedDB.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/OverdueTestSuiteWithEmbeddedDB.java
@@ -16,18 +16,21 @@
 
 package com.ning.billing.overdue;
 
+import javax.inject.Named;
+
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
 
 import com.ning.billing.GuicyKillbillTestSuiteWithEmbeddedDB;
 import com.ning.billing.bus.api.PersistentBus;
+import com.ning.billing.ovedue.notification.OverduePoster;
 import com.ning.billing.overdue.calculator.BillingStateCalculator;
 import com.ning.billing.notificationq.api.NotificationQueueService;
-import com.ning.billing.ovedue.notification.OverdueCheckNotifier;
-import com.ning.billing.ovedue.notification.OverdueCheckPoster;
+import com.ning.billing.ovedue.notification.OverdueNotifier;
 import com.ning.billing.overdue.applicator.OverdueBusListenerTester;
 import com.ning.billing.overdue.applicator.OverdueStateApplicator;
+import com.ning.billing.overdue.glue.DefaultOverdueModule;
 import com.ning.billing.overdue.glue.TestOverdueModuleWithEmbeddedDB;
 import com.ning.billing.overdue.service.DefaultOverdueService;
 import com.ning.billing.overdue.wrapper.OverdueWrapperFactory;
@@ -67,10 +70,18 @@ public abstract class OverdueTestSuiteWithEmbeddedDB extends GuicyKillbillTestSu
     protected NotificationQueueService notificationQueueService;
     @Inject
     protected OverdueBusListenerTester listener;
+    @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_CHECK_NAMED)
+    @Inject
+    protected OverdueNotifier checkNotifier;
+    @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_ASYNC_BUS_NAMED)
+    @Inject
+    protected OverdueNotifier asyncNotifier;
     @Inject
-    protected OverdueCheckNotifier notifier;
+    @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_CHECK_NAMED)
+    protected OverduePoster checkPoster;
     @Inject
-    protected OverdueCheckPoster poster;
+    @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_ASYNC_BUS_NAMED)
+    protected OverduePoster asyncPoster;
     @Inject
     protected OverdueStateApplicator applicator;
     @Inject