自定义oozie action 节点

本文介绍了如何在ApacheOozie5.1.0版本中自定义工作流操作,通过实现ActionExecutor接口来创建新的工作流节点。详细步骤包括实现接口方法如start(),end(),check(),kill()等,设置配置,编写xsd文件定义节点配置,以及在oozie服务中注册和部署自定义节点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

版本:oozie 5.1

官网文档地址:https://oozie.apache.org/docs/5.1.0/DG_CustomActionExecutor.html

实现步骤:

  • 实现 org.apache.oozie.action.ActionExecutor 接口
  • 修改oozie配置
  • 上传jar包
  • 重启服务

实现接口

实现 org.apache.oozie.action.ActionExecutor 接口

  • 调用父类 super(type) 方法,其中传入的 type 就是自定义类注册的类型名称
  • start() ,该方法会在调用节点的时候执行。在该方法中必须调用 setStartData() 方法,并且值不能为 null。如果想要实现跳过功能,还可以调用 setExecutionData() 方法直接将状态修改为成功。
  • end() ,该方法在节点正常执行结束的时候执行。在该方法中必须调用 setEndData() 方法,值同样不能为 null
  • check(),该方法用于检测节点是否执行完成。并且,如果是一个异步节点(异步节点,任务不是实际在oozie上执行的:比如一个hive节点,任务实际上提交到 yarn执行,那么 check 就是主动去 yarn 上查询状态),则必须实现该方法,并且在节点完成时,必须调用 setExecutionData() 方法,如果节点仍然在执行,则必须调用 setExternalStatus() 方法
  • kill(),用于主动结束任务的实现。必须调用 setEndData() 方法
  • isCompleted(),判断当前节点是否为任务的终态

pom 依赖

<dependency>
    <groupId>org.apache.oozie</groupId>
    <artifactId>oozie-core</artifactId>
    <version>5.1.0</version>
    <scope>provided</scope>
</dependency>

示例代码:比如我们要实现一个节点去调起一个外部程序,并要等待该程序执行完成,这里没有具体逻辑,只是简单的伪代码

package net.zhboom.node;

import org.apache.oozie.action.ActionExecutor;
import org.apache.oozie.action.ActionExecutorException;
import org.apache.oozie.client.WorkflowAction;

import java.util.HashSet;
import java.util.Set;

/**
 * @author zhboom
 * @date 2023/5/19
 */
public class CustomOozieAction extends ActionExecutor {

    private static final String ACTION_TYPE = "custom-oozie";

    private final CallExternalProgram callExternalProgram = new CallExternalProgram();

    public CustomOozieAction() {
        super(ACTION_TYPE);
    }

    @Override
    public void start(Context context, WorkflowAction action) throws ActionExecutorException {
        try {
            // 可以拿到 XML 中定义的内容
            Element eConf = XmlUtils.parseXml(action.getConf());
            Namespace ns = eConf.getNamespace();
            String executePath = eConf.getChild("executor-path", ns).getTextTrim();
            String command = eConf.getChild("command", ns).getTextTrim();
            
            callExternalProgram.start();
            // 这里的数据根据后边会用到
            context.setStartData("-", "-", "-");
        } catch (JDOMException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void end(Context context, WorkflowAction action) throws ActionExecutorException {
        // 这里是复制的子工作流节点的逻辑
        String externalStatus = action.getExternalStatus();
        WorkflowAction.Status status = externalStatus.equals("SUCCEEDED") ? WorkflowAction.Status.OK
                : WorkflowAction.Status.ERROR;
        context.setEndData(status, getActionSignal(status));
    }

    @Override
    public void check(Context context, WorkflowAction action) throws ActionExecutorException {
        Status status = callExternalProgram.checkStatus();
        switch (status) {
            case FAILED:
            case SUCCESS:
            context.setExecutionData("对应的状态", null);
            break;
            default:
                context.setExternalStatus("对应的状态");
        }
    }

    @Override
    public void kill(Context context, WorkflowAction action) throws ActionExecutorException {
        callExternalProgram.shutdown();
        context.setEndData(WorkflowAction.Status.KILLED, getActionSignal(WorkflowAction.Status.KILLED));
    }

    private static Set<String> FINAL_STATUS = new HashSet<String>();

    static {
        FINAL_STATUS.add("SUCCEEDED");
        FINAL_STATUS.add("KILLED");
        FINAL_STATUS.add("FAILED");
    }

    @Override
    public boolean isCompleted(String externalStatus) {
        return FINAL_STATUS.contains(externalStatus);
    }


    static class CallExternalProgram {
        public void start() {
            // 调用外部程序
        }

        public Status checkStatus() {
            return Status.SUCCESS;
        }

        public void shutdown() {
            // 终止外部程序
        }
    }

    public enum Status {
        SUCCESS, FAILED
    }
}

resource 目录下新建文件 customOozieAction.xsd,这里的数据可以通过参数 action 拿到。

有关 .xsd 文件的定义可自定百度

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:customOozie="uri:custom:oozie-action:0.1"
           elementFormDefault="qualified"
           targetNamespace="uri:custom:oozie-action:0.1"
>

    <xs:complexType name="CONFIGURATION">
        <xs:sequence>
            <xs:element name="property" minOccurs="1" maxOccurs="unbounded">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="name" minOccurs="1" maxOccurs="1" type="xs:string"/>
                        <xs:element name="value" minOccurs="1" maxOccurs="1" type="xs:string"/>
                        <xs:element name="description" minOccurs="0" maxOccurs="1" type="xs:string"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="FLAG"/>

    <xs:complexType name="CUSTOM-OOZIE">
        <xs:sequence>
            <xs:element name="app-path" type="xs:string" minOccurs="1" maxOccurs="1"/>
            <xs:element name="propagate-configuration" type="customOozie:FLAG" minOccurs="0" maxOccurs="1"/>
            <!-- 外部程序地址 -->
            <xs:element name="executor-path" type="xs:string" />
            <!-- 外部程序执行指令 -->
            <xs:element name="command" type="xs:string" />
            <xs:element name="configuration" type="customOozie:CONFIGURATION" minOccurs="0" maxOccurs="1"/>
        </xs:sequence>
    </xs:complexType>

    <xs:element name="custom-oozie" type="customOozie:CUSTOM-OOZIE"/>
</xs:schema>

修改 oozie 配置

oozie-site.xml 文件中修改配置 ,多个用英文逗号分割

  • oozie.service.ActionService.executor.ext.classesnet.zhboom.node.CustomOozieAction
  • oozie.service.SchemaService.wf.ext.schemascustomOozieAction.xsd
<property>
    <name>oozie.service.ActionService.executor.ext.classes</name>
    <value>net.zhboom.node.CustomOozieAction</value>
  </property>
<property>
    <name>oozie.service.SchemaService.wf.ext.schemas</name>
    <value>customOozieAction.xsd</value>
</property>

上传 jar 包

将代码打包,并上传到 oozie server 对应的 libext/ 目录下(注意修改文件的权限)

如果有多台服务,则每台都要放

重启

然后重启 oozie 服务就可以使用自定义节点了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值