org.apache.oozie.command.wf.ActionStartCommand.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.oozie.command.wf.ActionStartCommand.java

Source

/**
 * Copyright (c) 2010 Yahoo! Inc. 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. See accompanying LICENSE file.
 */
package org.apache.oozie.command.wf;

import java.util.Date;

import javax.servlet.jsp.el.ELException;

import org.apache.hadoop.conf.Configuration;
import org.apache.oozie.ErrorCode;
import org.apache.oozie.FaultInjection;
import org.apache.oozie.WorkflowActionBean;
import org.apache.oozie.WorkflowJobBean;
import org.apache.oozie.XException;
import org.apache.oozie.action.ActionExecutor;
import org.apache.oozie.action.ActionExecutorException;
import org.apache.oozie.client.OozieClient;
import org.apache.oozie.client.WorkflowAction;
import org.apache.oozie.client.WorkflowJob;
import org.apache.oozie.client.SLAEvent.SlaAppType;
import org.apache.oozie.client.SLAEvent.Status;
import org.apache.oozie.command.CommandException;
import org.apache.oozie.command.coord.CoordActionUpdateCommand;
import org.apache.oozie.service.ActionService;
import org.apache.oozie.service.Services;
import org.apache.oozie.service.UUIDService;
import org.apache.oozie.store.StoreException;
import org.apache.oozie.store.WorkflowStore;
import org.apache.oozie.util.ELEvaluationException;
import org.apache.oozie.util.Instrumentation;
import org.apache.oozie.util.XLog;
import org.apache.oozie.util.XmlUtils;
import org.apache.oozie.util.db.SLADbOperations;

public class ActionStartCommand extends ActionCommand<Void> {
    public static final String EL_ERROR = "EL_ERROR";
    public static final String EL_EVAL_ERROR = "EL_EVAL_ERROR";
    public static final String COULD_NOT_START = "COULD_NOT_START";
    public static final String START_DATA_MISSING = "START_DATA_MISSING";
    public static final String EXEC_DATA_MISSING = "EXEC_DATA_MISSING";

    private String id;
    private String jobId;

    public ActionStartCommand(String id, String type) {
        super("action.start", type, 0);
        this.id = id;
    }

    @Override
    protected Void call(WorkflowStore store) throws StoreException, CommandException {
        WorkflowJobBean workflow = store.getWorkflow(jobId, false);
        setLogInfo(workflow);
        WorkflowActionBean action = store.getAction(id, false);
        XLog.getLog(getClass()).warn(XLog.STD,
                "[***" + action.getId() + "***]" + "In call()....status=" + action.getStatusStr());
        setLogInfo(action);
        if (action.isPending() && (action.getStatus() == WorkflowActionBean.Status.PREP
                || action.getStatus() == WorkflowActionBean.Status.START_RETRY
                || action.getStatus() == WorkflowActionBean.Status.START_MANUAL)) {
            if (workflow.getStatus() == WorkflowJob.Status.RUNNING) {

                ActionExecutor executor = Services.get().get(ActionService.class).getExecutor(action.getType());
                Configuration conf = workflow.getWorkflowInstance().getConf();

                int maxRetries = conf.getInt(OozieClient.ACTION_MAX_RETRIES, executor.getMaxRetries());
                long retryInterval = conf.getLong(OozieClient.ACTION_RETRY_INTERVAL, executor.getRetryInterval());
                executor.setMaxRetries(maxRetries);
                executor.setRetryInterval(retryInterval);

                if (executor != null) {
                    ActionExecutorContext context = null;
                    try {
                        boolean isRetry = false;
                        if (action.getStatus() == WorkflowActionBean.Status.START_RETRY
                                || action.getStatus() == WorkflowActionBean.Status.START_MANUAL) {
                            isRetry = true;
                        }
                        context = new ActionCommand.ActionExecutorContext(workflow, action, isRetry);
                        try {
                            String tmpActionConf = XmlUtils.removeComments(action.getConf());
                            String actionConf = context.getELEvaluator().evaluate(tmpActionConf, String.class);
                            action.setConf(actionConf);

                            XLog.getLog(getClass()).debug("Start, name [{0}] type [{1}] configuration{E}{E}{2}{E}",
                                    action.getName(), action.getType(), actionConf);

                        } catch (ELEvaluationException ex) {
                            throw new ActionExecutorException(ActionExecutorException.ErrorType.TRANSIENT,
                                    EL_EVAL_ERROR, ex.getMessage(), ex);
                        } catch (ELException ex) {
                            context.setErrorInfo(EL_ERROR, ex.getMessage());
                            XLog.getLog(getClass()).warn("ELException in ActionStartCommand ", ex.getMessage(), ex);
                            handleError(context, store, workflow, action);
                            return null;
                        } catch (org.jdom.JDOMException je) {
                            context.setErrorInfo("ParsingError", je.getMessage());
                            XLog.getLog(getClass()).warn("JDOMException in ActionStartCommand ", je.getMessage(),
                                    je);
                            handleError(context, store, workflow, action);
                            return null;
                        } catch (Exception ex) {
                            context.setErrorInfo(EL_ERROR, ex.getMessage());
                            XLog.getLog(getClass()).warn("Exception in ActionStartCommand ", ex.getMessage(), ex);
                            handleError(context, store, workflow, action);
                            return null;
                        }
                        action.setErrorInfo(null, null);
                        incrActionCounter(action.getType(), 1);

                        Instrumentation.Cron cron = new Instrumentation.Cron();
                        cron.start();
                        executor.start(context, action);
                        cron.stop();
                        FaultInjection.activate("org.apache.oozie.command.SkipCommitFaultInjection");
                        addActionCron(action.getType(), cron);

                        action.setRetries(0);
                        if (action.isExecutionComplete()) {
                            if (!context.isExecuted()) {
                                XLog.getLog(getClass()).warn(XLog.OPS,
                                        "Action Completed, ActionExecutor [{0}] must call setExecutionData()",
                                        executor.getType());
                                action.setErrorInfo(EXEC_DATA_MISSING,
                                        "Execution Complete, but Execution Data Missing from Action");
                                failJob(context);
                                store.updateAction(action);
                                store.updateWorkflow(workflow);
                                return null;
                            }
                            action.setPending();
                            queueCallable(new ActionEndCommand(action.getId(), action.getType()));
                        } else {
                            if (!context.isStarted()) {
                                XLog.getLog(getClass()).warn(XLog.OPS,
                                        "Action Started, ActionExecutor [{0}] must call setStartData()",
                                        executor.getType());
                                action.setErrorInfo(START_DATA_MISSING,
                                        "Execution Started, but Start Data Missing from Action");
                                failJob(context);
                                store.updateAction(action);
                                store.updateWorkflow(workflow);
                                return null;
                            }
                            queueCallable(new NotificationCommand(workflow, action));
                        }

                        XLog.getLog(getClass()).warn(XLog.STD,
                                "[***" + action.getId() + "***]" + "Action status=" + action.getStatusStr());

                        store.updateAction(action);
                        store.updateWorkflow(workflow);
                        // Add SLA status event (STARTED) for WF_ACTION
                        // SLADbOperations.writeSlaStatusEvent(eSla,
                        // action.getId(), Status.STARTED, store);
                        SLADbOperations.writeStausEvent(action.getSlaXml(), action.getId(), store, Status.STARTED,
                                SlaAppType.WORKFLOW_ACTION);
                        XLog.getLog(getClass()).warn(XLog.STD,
                                "[***" + action.getId() + "***]" + "Action updated in DB!");

                    } catch (ActionExecutorException ex) {
                        XLog.getLog(getClass()).warn(
                                "Error starting action [{0}]. ErrorType [{1}], ErrorCode [{2}], Message [{3}]",
                                action.getName(), ex.getErrorType(), ex.getErrorCode(), ex.getMessage(), ex);
                        action.setErrorInfo(ex.getErrorCode(), ex.getMessage());
                        switch (ex.getErrorType()) {
                        case TRANSIENT:
                            if (!handleTransient(context, executor, WorkflowAction.Status.START_RETRY)) {
                                handleNonTransient(store, context, executor, WorkflowAction.Status.START_MANUAL);
                                action.setPendingAge(new Date());
                                action.setRetries(0);
                                action.setStartTime(null);
                            }
                            break;
                        case NON_TRANSIENT:
                            handleNonTransient(store, context, executor, WorkflowAction.Status.START_MANUAL);
                            break;
                        case ERROR:
                            handleError(context, executor, WorkflowAction.Status.ERROR.toString(), true,
                                    WorkflowAction.Status.DONE);
                            break;
                        case FAILED:
                            try {
                                failJob(context);
                                queueCallable(new CoordActionUpdateCommand(workflow));
                                SLADbOperations.writeStausEvent(action.getSlaXml(), action.getId(), store,
                                        Status.FAILED, SlaAppType.WORKFLOW_ACTION);
                                SLADbOperations.writeStausEvent(workflow.getSlaXml(), workflow.getId(), store,
                                        Status.FAILED, SlaAppType.WORKFLOW_JOB);
                            } catch (XException x) {
                                XLog.getLog(getClass()).warn("ActionStartCommand - case:FAILED ", x.getMessage());
                            }
                            break;
                        }
                        store.updateAction(action);
                        store.updateWorkflow(workflow);
                    }
                } else {
                    throw new CommandException(ErrorCode.E0802, action.getType());
                }

            } else {
                XLog.getLog(getClass()).warn("Job state is not {0}. Skipping Action Execution",
                        WorkflowJob.Status.RUNNING.toString());
            }
        }
        return null;
    }

    private void handleError(ActionExecutorContext context, WorkflowStore store, WorkflowJobBean workflow,
            WorkflowActionBean action) throws CommandException, StoreException {
        failJob(context);
        store.updateAction(action);
        store.updateWorkflow(workflow);
        SLADbOperations.writeStausEvent(action.getSlaXml(), action.getId(), store, Status.FAILED,
                SlaAppType.WORKFLOW_ACTION);
        SLADbOperations.writeStausEvent(workflow.getSlaXml(), workflow.getId(), store, Status.FAILED,
                SlaAppType.WORKFLOW_JOB);
        queueCallable(new CoordActionUpdateCommand(workflow));
        return;
    }

    @Override
    protected Void execute(WorkflowStore store) throws CommandException, StoreException {
        try {
            XLog.getLog(getClass()).debug("STARTED ActionStartCommand for wf actionId=" + id);
            jobId = Services.get().get(UUIDService.class).getId(id);
            if (lock(jobId)) {
                call(store);
            } else {
                queueCallable(new ActionStartCommand(id, type), LOCK_FAILURE_REQUEUE_INTERVAL);
                XLog.getLog(getClass()).warn("ActionStartCommand lock was not acquired - failed {0}", id);
            }
        } catch (InterruptedException e) {
            queueCallable(new ActionStartCommand(id, type), LOCK_FAILURE_REQUEUE_INTERVAL);
            XLog.getLog(getClass())
                    .warn("ActionStartCommand lock was not acquired - interrupted exception failed {0}", id);
        }
        XLog.getLog(getClass()).debug("ENDED ActionStartCommand for wf actionId=" + id + ", jobId=" + jobId);
        return null;
    }

}