org.wso2.andes.kernel.PreDeliveryExpiryMessageDeletionTask.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.andes.kernel.PreDeliveryExpiryMessageDeletionTask.java

Source

/*
 * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * 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 org.wso2.andes.kernel;

import com.google.common.util.concurrent.SettableFuture;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.andes.configuration.AndesConfigurationManager;
import org.wso2.andes.configuration.enums.AndesConfiguration;
import org.wso2.andes.store.FailureObservingStoreManager;
import org.wso2.andes.store.HealthAwareStore;
import org.wso2.andes.store.StoreHealthListener;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.LinkedBlockingDeque;

/**
 * This task is responsible for delete ths expired messages captured from the message flusher.
 * Those captured messages accumulated in a set for a batch delete. This task is responsible to do
 * that batch delete.
 */
public class PreDeliveryExpiryMessageDeletionTask implements Runnable, StoreHealthListener {

    private static Log log = LogFactory.getLog(PreDeliveryExpiryMessageDeletionTask.class);

    /**
     * Holds expired messages detected in the message flusher delivery rule check for batch delete
     */
    private BlockingDeque<DeliverableAndesMetadata> expiredMessages;

    /**
     * Indicates and provides a barrier if messages stores become offline.
     * marked as volatile since this value could be set from a different thread
     */
    private volatile SettableFuture<Boolean> messageStoresUnavailable;

    /**
     * Indicates to expired messages should move to DLC
     */
    private Boolean moveExpiredToDLC;

    /**
     * Create a task that keeps expired messages and delete them in batches.
     */
    PreDeliveryExpiryMessageDeletionTask() {
        this.messageStoresUnavailable = null;
        this.messageStoresUnavailable = null;
        this.moveExpiredToDLC = AndesConfigurationManager
                .readValue(AndesConfiguration.PERFORMANCE_TUNING_MOVE_EXPIRED_MESSAGES_TO_DLC);
        this.expiredMessages = new LinkedBlockingDeque<>();
        // Register AndesRecoveryTask class as a StoreHealthListener
        FailureObservingStoreManager.registerStoreHealthListener(this);
    }

    /**
     * Add an expired message to be removed asynchronously
     *
     * @param expiredMessage expired message
     */
    void addMessageIdToExpiredQueue(DeliverableAndesMetadata expiredMessage) {
        expiredMessages.add(expiredMessage);
    }

    @Override
    public void run() {
        // Checks for the message store availability.
        // if its not available deletion task needs to await until message store becomes available
        if (null != messageStoresUnavailable) {

            try {
                log.info("Message store has become unavailable therefore expiry message deletion task is"
                        + "waiting until store becomes available");
                //act as a barrier
                messageStoresUnavailable.get();
                log.info("Message store became available. Resuming expiry message deletion task");
                messageStoresUnavailable = null; // we are passing the blockade (therefore clear the it).
            } catch (InterruptedException e) {
                log.error("Thread interrupted while waiting for message stores to come online", e);
            } catch (ExecutionException e) {
                log.error("Error occurred while waiting for message stores to come online", e);
            } catch (Throwable e) {
                log.error("Error occurred during the pre delivery expiry message deletion task", e);
            }

        }

        /*
         * delete the accumulated messages in the list that are filtered out from the message
         * flusher expiration rule should be run in all the nodes
         */
        if (!expiredMessages.isEmpty()) {
            try {
                List<DeliverableAndesMetadata> expiredMessagesList = new ArrayList<>();
                expiredMessages.drainTo(expiredMessagesList);
                if (moveExpiredToDLC) {
                    MessagingEngine.getInstance().moveMessageToDeadLetterChannel(expiredMessagesList);
                } else {
                    MessagingEngine.getInstance().deleteMessages(expiredMessagesList);
                }
            } catch (AndesException e) {
                log.error("Error running message expiration checker ", e);
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void storeNonOperational(HealthAwareStore store, Exception ex) {
        log.warn("Message store became not operational.");
        messageStoresUnavailable = SettableFuture.create();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void storeOperational(HealthAwareStore store) {
        log.info("Message store became operational.");
        messageStoresUnavailable.set(false);
    }

}