Package org.apache.airavata.gfac.monitor.impl.push.amqp

Source Code of org.apache.airavata.gfac.monitor.impl.push.amqp.AMQPMonitor

/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF 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 org.apache.airavata.gfac.monitor.impl.push.amqp;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import org.apache.airavata.common.utils.ServerSettings;
import org.apache.airavata.commons.gfac.type.HostDescription;
import org.apache.airavata.gfac.core.monitor.JobIdentity;
import org.apache.airavata.gfac.core.monitor.MonitorID;
import org.apache.airavata.gfac.core.monitor.state.JobStatusChangeRequest;
import org.apache.airavata.gfac.core.notification.MonitorPublisher;
import org.apache.airavata.gfac.monitor.core.PushMonitor;
import org.apache.airavata.gfac.monitor.exception.AiravataMonitorException;
import org.apache.airavata.gfac.monitor.util.AMQPConnectionUtil;
import org.apache.airavata.gfac.monitor.util.CommonUtils;
import org.apache.airavata.model.workspace.experiment.JobState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.BlockingQueue;

/**
* This is the implementation for AMQP based finishQueue, this uses
* rabbitmq client to recieve AMQP based monitoring data from
* mostly excede resources.
*/
public class AMQPMonitor extends PushMonitor {
    private final static Logger logger = LoggerFactory.getLogger(AMQPMonitor.class);


    /* this will keep all the channels available in the system, we do not create
      channels for all the jobs submitted, but we create channels for each user for each
      host.
    */
    private Map<String, Channel> availableChannels;

    private MonitorPublisher publisher;

    private MonitorPublisher localPublisher;

    private BlockingQueue<MonitorID> runningQueue;

    private BlockingQueue<MonitorID> finishQueue;

    private String connectionName;

    private String proxyPath;

    private List<String> amqpHosts;

    private boolean startRegister;

    public AMQPMonitor(){

    }
    public AMQPMonitor(MonitorPublisher publisher, BlockingQueue<MonitorID> runningQueue,
                       BlockingQueue<MonitorID> finishQueue,
                       String proxyPath,String connectionName,List<String> hosts) {
        this.publisher = publisher;
        this.runningQueue = runningQueue;        // these will be initialized by the MonitorManager
        this.finishQueue = finishQueue;          // these will be initialized by the MonitorManager
        this.availableChannels = new HashMap<String, Channel>();
        this.connectionName = connectionName;
        this.proxyPath = proxyPath;
        this.amqpHosts = hosts;
        this.localPublisher = new MonitorPublisher(new EventBus());
        this.localPublisher.registerListener(this);
    }

    public void initialize(String proxyPath, String connectionName, List<String> hosts) {
        this.availableChannels = new HashMap<String, Channel>();
        this.connectionName = connectionName;
        this.proxyPath = proxyPath;
        this.amqpHosts = hosts;
        this.localPublisher = new MonitorPublisher(new EventBus());
        this.localPublisher.registerListener(this);
    }

    @Override
    public boolean registerListener(MonitorID monitorID) throws AiravataMonitorException {
        // we subscribe to read user-host based subscription
        HostDescription host = monitorID.getHost();
        String hostAddress = host.getType().getHostAddress();
        // in amqp case there are no multiple jobs per each host, because once a job is put in to the queue it
        // will be picked by the Monitor, so jobs will not stay in this queueu but jobs will stay in finishQueue
        String channelID = CommonUtils.getChannelID(monitorID);
        if(availableChannels.get(channelID) == null){
        try {
            //todo need to fix this rather getting it from a file
            Connection connection = AMQPConnectionUtil.connect(amqpHosts, connectionName, proxyPath);
            Channel channel = null;
            channel = connection.createChannel();
            availableChannels.put(channelID, channel);
            String queueName = channel.queueDeclare().getQueue();

            BasicConsumer consumer = new
                    BasicConsumer(new JSONMessageParser(), localPublisher);          // here we use local publisher
            channel.basicConsume(queueName, true, consumer);
            String filterString = CommonUtils.getRoutingKey(monitorID.getUserName(), hostAddress);
            // here we queuebind to a particular user in a particular machine
            channel.queueBind(queueName, "glue2.computing_activity", filterString);
            logger.info("Using filtering string to monitor: " + filterString);
        } catch (IOException e) {
            logger.error("Error creating the connection to finishQueue the job:" + monitorID.getUserName());
        }
        }
        return true;
    }

    public void run() {
        // before going to the while true mode we start unregister thread
        startRegister = true; // this will be unset by someone else
        while (startRegister || !ServerSettings.isStopAllThreads()) {
            try {
                MonitorID take = runningQueue.take();
                this.registerListener(take);
            } catch (AiravataMonitorException e) { // catch any exceptino inside the loop
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace()//To change body of catch statement use File | Settings | File Templates.
            } catch (Exception e){
                e.printStackTrace();
            }
        }
        Set<String> strings = availableChannels.keySet();
        for(String key:strings) {
            Channel channel = availableChannels.get(key);
            try {
                channel.close();
            } catch (IOException e) {
                e.printStackTrace()//To change body of catch statement use File | Settings | File Templates.
            }
        }
    }

    @Subscribe
    public boolean unRegisterListener(MonitorID monitorID) throws AiravataMonitorException {
        Iterator<MonitorID> iterator = finishQueue.iterator();
        MonitorID next = null;
        while(iterator.hasNext()){
            next = iterator.next();
            if(next.getJobID().endsWith(monitorID.getJobID())){
                break;
            }
        }
        if(next == null) {
            logger.error("Job has removed from the queue, old obsolete message recieved");
            return false;
        }
        String channelID = CommonUtils.getChannelID(next);
        if (JobState.FAILED.equals(monitorID.getStatus()) || JobState.COMPLETE.equals(monitorID.getStatus())) {
            finishQueue.remove(next);

            // if this is the last job in the queue at this point with the same username and same host we
            // close the channel and close the connection and remove it from availableChannels
            if (CommonUtils.isTheLastJobInQueue(finishQueue, next)) {
                logger.info("There are no jobs to monitor for common ChannelID:" + channelID + " , so we unsubscribe it" +
                        ", incase new job created we do subscribe again");
                Channel channel = availableChannels.get(channelID);
                if (channel == null) {
                    logger.error("Already Unregistered the listener");
                    throw new AiravataMonitorException("Already Unregistered the listener");
                } else {
                    try {
                        channel.queueUnbind(channel.queueDeclare().getQueue(), "glue2.computing_activity", CommonUtils.getRoutingKey(next));
                        channel.close();
                        channel.getConnection().close();
                        availableChannels.remove(channelID);
                    } catch (IOException e) {
                        logger.error("Error unregistering the listener");
                        throw new AiravataMonitorException("Error unregistering the listener");
                    }
                }
            }
        }
        next.setStatus(monitorID.getStatus());
        publisher.publish(new JobStatusChangeRequest(next, new JobIdentity(next.getExperimentID(), next.getWorkflowNodeID(), next.getTaskID(), next.getJobID()),next.getStatus()));
        return true;
    }
    @Override
    public boolean stopRegister() throws AiravataMonitorException {
        return false//To change body of implemented methods use File | Settings | File Templates.
    }

    public Map<String, Channel> getAvailableChannels() {
        return availableChannels;
    }

    public void setAvailableChannels(Map<String, Channel> availableChannels) {
        this.availableChannels = availableChannels;
    }

    public MonitorPublisher getPublisher() {
        return publisher;
    }

    public void setPublisher(MonitorPublisher publisher) {
        this.publisher = publisher;
    }

    public BlockingQueue<MonitorID> getRunningQueue() {
        return runningQueue;
    }

    public void setRunningQueue(BlockingQueue<MonitorID> runningQueue) {
        this.runningQueue = runningQueue;
    }

    public BlockingQueue<MonitorID> getFinishQueue() {
        return finishQueue;
    }

    public void setFinishQueue(BlockingQueue<MonitorID> finishQueue) {
        this.finishQueue = finishQueue;
    }

    public String getProxyPath() {
        return proxyPath;
    }

    public void setProxyPath(String proxyPath) {
        this.proxyPath = proxyPath;
    }

    public List<String> getAmqpHosts() {
        return amqpHosts;
    }

    public void setAmqpHosts(List<String> amqpHosts) {
        this.amqpHosts = amqpHosts;
    }

    public boolean isStartRegister() {
        return startRegister;
    }

    public void setStartRegister(boolean startRegister) {
        this.startRegister = startRegister;
    }
}
TOP

Related Classes of org.apache.airavata.gfac.monitor.impl.push.amqp.AMQPMonitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.