001    /**
002     * Copyright (c) 2010 Yahoo! Inc. All rights reserved.
003     * Licensed under the Apache License, Version 2.0 (the "License");
004     * you may not use this file except in compliance with the License.
005     * You may obtain a copy of the License at
006     *
007     *   http://www.apache.org/licenses/LICENSE-2.0
008     *
009     *  Unless required by applicable law or agreed to in writing, software
010     *  distributed under the License is distributed on an "AS IS" BASIS,
011     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012     *  See the License for the specific language governing permissions and
013     *  limitations under the License. See accompanying LICENSE file.
014     */
015    package org.apache.oozie.command.coord;
016    
017    import java.util.List;
018    
019    import org.apache.oozie.CoordinatorActionBean;
020    import org.apache.oozie.CoordinatorJobBean;
021    import org.apache.oozie.client.CoordinatorAction;
022    import org.apache.oozie.command.CommandException;
023    import org.apache.oozie.store.CoordinatorStore;
024    import org.apache.oozie.store.StoreException;
025    import org.apache.oozie.util.XLog;
026    
027    public class CoordActionReadyCommand extends CoordinatorCommand<Void> {
028        private String jobId;
029        private final XLog log = XLog.getLog(getClass());
030    
031        public CoordActionReadyCommand(String id) {
032            super("coord_action_ready", "coord_action_ready", 1, XLog.STD);
033            this.jobId = id;
034        }
035    
036        @Override
037        /**
038         * Check for READY actions and change state to SUBMITTED by a command to submit the job to WF engine.
039         * This method checks all the actions associated with a jobId to figure out which actions
040         * to start (based on concurrency and execution order [FIFO, LIFO, LAST_ONLY])
041         *
042         * @param store Coordinator Store
043         */
044        protected Void call(CoordinatorStore store) throws StoreException, CommandException {
045            // number of actions to start (-1 means start ALL)
046            int numActionsToStart = -1;
047            // get CoordinatorJobBean for jobId
048            //CoordinatorJobBean coordJob = store.getCoordinatorJob(jobId, false);
049            CoordinatorJobBean coordJob = store.getEntityManager().find(CoordinatorJobBean.class, jobId);
050            setLogInfo(coordJob);
051            // get execution setting for this job (FIFO, LIFO, LAST_ONLY)
052            String jobExecution = coordJob.getExecution();
053            // get concurrency setting for this job
054            int jobConcurrency = coordJob.getConcurrency();
055            // if less than 0, then UNLIMITED concurrency
056            if (jobConcurrency >= 0) {
057                // count number of actions that are already RUNNING or SUBMITTED
058                // subtract from CONCURRENCY to calculate number of actions to start
059                // in WF engine
060                int numRunningJobs = store.getCoordinatorRunningActionsCount(jobId);
061                numActionsToStart = jobConcurrency - numRunningJobs;
062                if (numActionsToStart < 0) {
063                    numActionsToStart = 0;
064                }
065                log.debug("concurrency=" + jobConcurrency + ", execution=" + jobExecution + ", numRunningJobs="
066                        + numRunningJobs + ", numLeftover=" + numActionsToStart);
067                // no actions to start
068                if (numActionsToStart == 0) {
069                    log.warn("No actions to start! for jobId=" + jobId);
070                    return null;
071                }
072            }
073            // get list of actions that are READY and fit in the concurrency and
074            // execution
075            List<CoordinatorActionBean> actions = store.getCoordinatorActionsForJob(jobId, numActionsToStart, jobExecution);
076            log.debug("Number of READY actions = " + actions.size());
077            String user = coordJob.getUser();
078            String authToken = coordJob.getAuthToken();
079            // make sure auth token is not null
080            // log.denug("user=" + user + ", token=" + authToken);
081            int counter = 0;
082            for (CoordinatorActionBean action : actions) {
083                // continue if numActionsToStart is negative (no limit on number of
084                // actions), or if the counter is less than numActionsToStart
085                if ((numActionsToStart < 0) || (counter < numActionsToStart)) {
086                    log.debug("Set status to SUBMITTED for id: " + action.getId());
087                    // change state of action to SUBMITTED
088                    action.setStatus(CoordinatorAction.Status.SUBMITTED);
089                    // queue action to start action
090                    queueCallable(new CoordActionStartCommand(action.getId(), user, authToken), 100);
091                    store.updateCoordinatorAction(action);
092                }
093                else {
094                    break;
095                }
096                counter++;
097    
098            }
099            return null;
100        }
101    
102        @Override
103        protected Void execute(CoordinatorStore store) throws StoreException, CommandException {
104            log.info("STARTED CoordActionReadyCommand for jobId=" + jobId);
105            try {
106                if (lock(jobId)) {
107                    call(store);
108                }
109                else {
110                    queueCallable(new CoordActionReadyCommand(jobId), LOCK_FAILURE_REQUEUE_INTERVAL);
111                    log.warn("CoordActionReadyCommand lock was not acquired - failed jobId=" + jobId
112                            + ". Requeing the same.");
113                }
114            }
115            catch (InterruptedException e) {
116                queueCallable(new CoordActionReadyCommand(jobId), LOCK_FAILURE_REQUEUE_INTERVAL);
117                log.warn("CoordActionReadyCommand lock acquiring failed with exception " + e.getMessage()
118                        + " for jobId=" + jobId + " Requeing the same.");
119            }
120            finally {
121                log.info("ENDED CoordActionReadyCommand for jobId=" + jobId);
122            }
123            return null;
124        }
125    
126    }