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.ErrorCode; 022 import org.apache.oozie.client.CoordinatorAction; 023 import org.apache.oozie.client.Job; 024 import org.apache.oozie.command.CommandException; 025 import org.apache.oozie.command.PreconditionException; 026 import org.apache.oozie.executor.jpa.CoordJobGetReadyActionsJPAExecutor; 027 import org.apache.oozie.executor.jpa.CoordJobGetRunningActionsCountJPAExecutor; 028 import org.apache.oozie.executor.jpa.JPAExecutorException; 029 import org.apache.oozie.service.JPAService; 030 import org.apache.oozie.service.Services; 031 import org.apache.oozie.util.LogUtils; 032 import org.apache.oozie.util.XLog; 033 034 public class CoordActionReadyXCommand extends CoordinatorXCommand<Void> { 035 private final String jobId; 036 private final XLog log = getLog(); 037 private CoordinatorJobBean coordJob = null; 038 private JPAService jpaService = null; 039 040 public CoordActionReadyXCommand(String id) { 041 super("coord_action_ready", "coord_action_ready", 1); 042 this.jobId = id; 043 } 044 045 @Override 046 /** 047 * Check for READY actions and change state to SUBMITTED by a command to submit the job to WF engine. 048 * This method checks all the actions associated with a jobId to figure out which actions 049 * to start (based on concurrency and execution order [FIFO, LIFO, LAST_ONLY]) 050 * 051 */ 052 protected Void execute() throws CommandException { 053 // number of actions to start (-1 means start ALL) 054 int numActionsToStart = -1; 055 056 // get execution setting for this job (FIFO, LIFO, LAST_ONLY) 057 String jobExecution = coordJob.getExecution(); 058 // get concurrency setting for this job 059 int jobConcurrency = coordJob.getConcurrency(); 060 // if less than 0, then UNLIMITED concurrency 061 if (jobConcurrency >= 0) { 062 // count number of actions that are already RUNNING or SUBMITTED 063 // subtract from CONCURRENCY to calculate number of actions to start 064 // in WF engine 065 066 int numRunningJobs; 067 try { 068 numRunningJobs = jpaService.execute(new CoordJobGetRunningActionsCountJPAExecutor(jobId)); 069 } 070 catch (JPAExecutorException je) { 071 throw new CommandException(je); 072 } 073 074 numActionsToStart = jobConcurrency - numRunningJobs; 075 if (numActionsToStart < 0) { 076 numActionsToStart = 0; 077 } 078 log.debug("concurrency=" + jobConcurrency + ", execution=" + jobExecution + ", numRunningJobs=" 079 + numRunningJobs + ", numLeftover=" + numActionsToStart); 080 // no actions to start 081 if (numActionsToStart == 0) { 082 log.warn("No actions to start! for jobId=" + jobId); 083 return null; 084 } 085 } 086 // get list of actions that are READY and fit in the concurrency and execution 087 088 List<CoordinatorActionBean> actions; 089 try { 090 actions = jpaService.execute(new CoordJobGetReadyActionsJPAExecutor(jobId, numActionsToStart, jobExecution)); 091 } 092 catch (JPAExecutorException je) { 093 throw new CommandException(je); 094 } 095 log.debug("Number of READY actions = " + actions.size()); 096 String user = coordJob.getUser(); 097 String authToken = coordJob.getAuthToken(); 098 // make sure auth token is not null 099 // log.denug("user=" + user + ", token=" + authToken); 100 int counter = 0; 101 for (CoordinatorActionBean action : actions) { 102 // continue if numActionsToStart is negative (no limit on number of 103 // actions), or if the counter is less than numActionsToStart 104 if ((numActionsToStart < 0) || (counter < numActionsToStart)) { 105 log.debug("Set status to SUBMITTED for id: " + action.getId()); 106 // change state of action to SUBMITTED 107 action.setStatus(CoordinatorAction.Status.SUBMITTED); 108 // queue action to start action 109 queue(new CoordActionStartXCommand(action.getId(), user, authToken), 100); 110 try { 111 jpaService.execute(new org.apache.oozie.executor.jpa.CoordActionUpdateJPAExecutor(action)); 112 } 113 catch (JPAExecutorException je) { 114 throw new CommandException(je); 115 } 116 } 117 else { 118 break; 119 } 120 counter++; 121 122 } 123 return null; 124 } 125 126 @Override 127 protected String getEntityKey() { 128 return jobId; 129 } 130 131 @Override 132 protected boolean isLockRequired() { 133 return true; 134 } 135 136 @Override 137 protected void loadState() throws CommandException { 138 jpaService = Services.get().get(JPAService.class); 139 if (jpaService == null) { 140 throw new CommandException(ErrorCode.E0610); 141 } 142 try { 143 coordJob = jpaService.execute(new org.apache.oozie.executor.jpa.CoordJobGetJPAExecutor(jobId)); 144 } 145 catch (JPAExecutorException e) { 146 throw new CommandException(e); 147 } 148 LogUtils.setLogInfo(coordJob, logInfo); 149 } 150 151 @Override 152 protected void verifyPrecondition() throws CommandException, PreconditionException { 153 if (coordJob.getStatus() != Job.Status.RUNNING && coordJob.getStatus() != Job.Status.SUCCEEDED && coordJob.getStatus() != Job.Status.PAUSED && coordJob.getStatus() != Job.Status.PAUSEDWITHERROR) { 154 throw new PreconditionException(ErrorCode.E1100, "[" + jobId 155 + "]::CoordActionReady:: Ignoring job. Coordinator job is not in RUNNING state, but state=" 156 + coordJob.getStatus()); 157 } 158 } 159 }