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.wf; 016 017 import java.sql.Timestamp; 018 import java.util.Date; 019 020 import org.apache.oozie.WorkflowActionBean; 021 import org.apache.oozie.WorkflowJobBean; 022 import org.apache.oozie.action.ActionExecutor; 023 import org.apache.oozie.action.ActionExecutorException; 024 import org.apache.oozie.client.WorkflowJob; 025 import org.apache.oozie.client.WorkflowAction.Status; 026 import org.apache.oozie.command.CommandException; 027 import org.apache.oozie.service.ActionService; 028 import org.apache.oozie.service.Services; 029 import org.apache.oozie.service.UUIDService; 030 import org.apache.oozie.store.StoreException; 031 import org.apache.oozie.store.WorkflowStore; 032 import org.apache.oozie.util.Instrumentation; 033 import org.apache.oozie.util.XLog; 034 035 /** 036 * Executes the check command for ActionHandlers. </p> Ensures the action is in RUNNING state before executing {@link 037 * ActionExecutor#check(org.apache.oozie.action.ActionExecutor.Context, org.apache.oozie.client.WorkflowAction)} 038 */ 039 public class ActionCheckCommand extends ActionCommand<Void> { 040 public static final String EXEC_DATA_MISSING = "EXEC_DATA_MISSING"; 041 private String id; 042 private String jobId; 043 private int actionCheckDelay; 044 045 public ActionCheckCommand(String id) { 046 this(id, -1); 047 } 048 049 public ActionCheckCommand(String id, int priority, int checkDelay) { 050 super("action.check", "action.check", priority); 051 this.id = id; 052 this.actionCheckDelay = checkDelay; 053 } 054 055 public ActionCheckCommand(String id, int checkDelay) { 056 this(id, 0, checkDelay); 057 } 058 059 @Override 060 protected Void call(WorkflowStore store) throws StoreException, CommandException { 061 062 // String jobId = Services.get().get(UUIDService.class).getId(id); 063 WorkflowJobBean workflow = store.getWorkflow(jobId, false); 064 setLogInfo(workflow); 065 WorkflowActionBean action = store.getAction(id, false); 066 setLogInfo(action); 067 if (action.isPending() && action.getStatus() == WorkflowActionBean.Status.RUNNING) { 068 setLogInfo(workflow); 069 // if the action has been updated, quit this command 070 if (actionCheckDelay > 0) { 071 Timestamp actionCheckTs = new Timestamp(System.currentTimeMillis() - actionCheckDelay * 1000); 072 Timestamp actionLmt = action.getLastCheckTimestamp(); 073 if (actionLmt.after(actionCheckTs)) { 074 XLog.getLog(getClass()).debug( 075 "The wf action :" + id + " has been udated recently. Ignoring ActionCheckCommand!"); 076 return null; 077 } 078 } 079 if (workflow.getStatus() == WorkflowJob.Status.RUNNING) { 080 ActionExecutor executor = Services.get().get(ActionService.class).getExecutor(action.getType()); 081 if (executor != null) { 082 ActionExecutorContext context = null; 083 try { 084 boolean isRetry = false; 085 context = new ActionCommand.ActionExecutorContext(workflow, action, isRetry); 086 incrActionCounter(action.getType(), 1); 087 088 Instrumentation.Cron cron = new Instrumentation.Cron(); 089 cron.start(); 090 executor.check(context, action); 091 cron.stop(); 092 addActionCron(action.getType(), cron); 093 094 if (action.isExecutionComplete()) { 095 if (!context.isExecuted()) { 096 XLog.getLog(getClass()).warn(XLog.OPS, 097 "Action Completed, ActionExecutor [{0}] must call setExecutionData()", 098 executor.getType()); 099 action.setErrorInfo(EXEC_DATA_MISSING, 100 "Execution Complete, but Execution Data Missing from Action"); 101 failJob(context); 102 action.setLastCheckTime(new Date()); 103 store.updateAction(action); 104 store.updateWorkflow(workflow); 105 return null; 106 } 107 action.setPending(); 108 queueCallable(new ActionEndCommand(action.getId(), action.getType())); 109 } 110 action.setLastCheckTime(new Date()); 111 store.updateAction(action); 112 store.updateWorkflow(workflow); 113 } 114 catch (ActionExecutorException ex) { 115 XLog.getLog(getClass()).warn( 116 "Exception while executing check(). Error Code [{0}], Message[{1}]", ex.getErrorCode(), 117 ex.getMessage(), ex); 118 119 switch (ex.getErrorType()) { 120 case FAILED: 121 failAction(workflow, action); 122 break; 123 } 124 action.setLastCheckTime(new Date()); 125 store.updateAction(action); 126 store.updateWorkflow(workflow); 127 return null; 128 } 129 } 130 } 131 else { 132 action.setLastCheckTime(new Date()); 133 store.updateAction(action); 134 XLog.getLog(getClass()).warn( 135 "Action [{0}] status is running but WF Job [{1}] status is [{2}]. Expected status is RUNNING.", 136 action.getId(), workflow.getId(), workflow.getStatus()); 137 } 138 } 139 return null; 140 } 141 142 private void failAction(WorkflowJobBean workflow, WorkflowActionBean action) throws CommandException { 143 XLog.getLog(getClass()).warn("Failing Job [{0}] due to failed action [{1}]", workflow.getId(), action.getId()); 144 action.resetPending(); 145 action.setStatus(Status.FAILED); 146 workflow.setStatus(WorkflowJob.Status.FAILED); 147 incrJobCounter(INSTR_FAILED_JOBS_COUNTER, 1); 148 } 149 150 /** 151 * @param args 152 * @throws Exception 153 */ 154 public static void main(String[] args) throws Exception { 155 new Services().init(); 156 157 try { 158 new ActionCheckCommand("0000001-100122154231282-oozie-dani-W@pig1").call(); 159 Thread.sleep(100000); 160 } 161 finally { 162 new Services().destroy(); 163 } 164 } 165 166 @Override 167 protected Void execute(WorkflowStore store) throws CommandException, StoreException { 168 try { 169 XLog.getLog(getClass()).debug("STARTED ActionCheckCommand for wf actionId=" + id + " priority =" + getPriority()); 170 jobId = Services.get().get(UUIDService.class).getId(id); 171 if (lock(jobId)) { 172 call(store); 173 } 174 else { 175 queueCallable(new ActionCheckCommand(id, actionCheckDelay), LOCK_FAILURE_REQUEUE_INTERVAL); 176 XLog.getLog(getClass()).warn("ActionCheckCommand lock was not acquired - failed {0}", id); 177 } 178 } 179 catch (InterruptedException e) { 180 queueCallable(new ActionCheckCommand(id, actionCheckDelay), LOCK_FAILURE_REQUEUE_INTERVAL); 181 XLog.getLog(getClass()).warn("ActionCheckCommand lock was not acquired - interrupted exception failed {0}", 182 id); 183 } 184 XLog.getLog(getClass()).debug("ENDED ActionCheckCommand for wf actionId=" + id + ", jobId=" + jobId); 185 return null; 186 } 187 }