一,介绍

本文使用Oozie的消息通知功能,并根据JMS规范中的消息选择器(Selector)实现 根据作业的ID来过滤消息。

首先搭建好JMS Provider(ActiveMQ) ,并进行相关配置,这样Oozie Server就可以把消息发送给JMS Provider了,我们使用了ActiveMQ作为消息服务器。相关配置可参考:Oozie 使用ActiveMQ实现 JMS通知

在ActiveMQ中配置好Topic,该Topic名称为${username}。即该${username}提交的所有的作业,作业的执行结果都会发送到名为${username}的Topic上。

对于Oozie而言,每提交一个作业会生成一个JobID,而我们的需求是,只对某些JobID感兴趣,并不是对该用户提交的所有作业感兴趣。因此,需要根据JobID来过滤订阅到${username}这个Topic上的消息。

二,实现JMS 消息选择器

根据JMS规范,在创建一个消费者时,可使用消息选择器。这样消费者就只能接收到被消息选择器过滤以后的消息了。而消息选择器使用 消息属性 和 消息头作为条件表达式,这些条件表达式使用boolean逻辑来声明应该将哪一条消息传递给JMS消费者。请注意:消息选择器无法参考消息体内的数据,它只能使用消息头和消息属性。

于是,我们就需要知道Oozie生成的JMS消息的消息头和消息属性是什么?参考官方文档可以看出,Oozie生成的JMS消息的头部由JMSHeaderConstants类来定义。其源代码如下:

 /**
  *
  * Class holding constants used in JMS selectors
  */
 public final class JMSHeaderConstants {
     // JMS Application specific properties for selectors
     public static final String EVENT_STATUS = "eventStatus";
     public static final String SLA_STATUS = "slaStatus";
     public static final String APP_NAME = "appName";
     public static final String USER = "user";
     public static final String MESSAGE_TYPE = "msgType";
     public static final String APP_TYPE = "appType";

     //public static final String JOBID = "jobId";// add for my specific selectors
     // JMS Header property
     public static final String MESSAGE_FORMAT = "msgFormat";

 }

从中可以看出,可以使用EVENT_STATUS、SLA_STATUS、USER……相关属性构造选择器。但是官方JMSHeaderConstants类的源代码中并没有JobID这个属性。

因此,需要修改源代码,添加JobID,以使得我们消费者能够根据JobID进行过滤。(如上,第14行就是我自己添加的代码)

此外,还需要在JobMessage类的构造方法里面添加一行:

        jmsMessageProperties.put(JMSHeaderConstants.JOBID, id);//add for my specific selectors

至此,Oozie端的代码修改完毕。

这两个类在oozie-client这个maven工程中

进入到该工程的文件夹下,使用

mvn clean compile

mvn clean package

生成相关的jar文件

将生成的oozie-client-4.1.0.jar文件替换掉原来的Oozie 安装目录下的lib包下的对应的jar包。重启Oozie即可。

另外,Apache Oozie-4.1.0是不支持Spark作业的。而Cloudera-Oozie-4.1.0则是支持Spark作业的。

Apache oozie-client.jar 与Cloudera的 oozie-client.jar对比如下:

5月 6, 中午12点09:47.473     FATAL     org.apache.oozie.service.Services     

SERVER[datanode1] Runtime Exception during Services Load. Check your list of 'oozie.services' or 'oozie.services.ext'

5月 6, 中午12点09:47.480     FATAL     org.apache.oozie.service.Services     

SERVER[datanode1] E0103: Could not load service classes, resource [spark-action-0.1.xsd] not found
org.apache.oozie.service.ServiceException: E0103: Could not load service classes, resource [spark-action-0.1.xsd] not found
    at org.apache.oozie.service.Services.loadServices(Services.java:309)
    at org.apache.oozie.service.Services.init(Services.java:213)
    at org.apache.oozie.servlet.ServicesLoader.contextInitialized(ServicesLoader.java:46)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4210)
    at org.apache.catalina.core.StandardContext.start(StandardContext.java:4709)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:802)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:779)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:583)
    at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:944)
    at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:779)
    at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:505)
    at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1322)
    at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:325)
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:142)
    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1068)
    at org.apache.catalina.core.StandardHost.start(StandardHost.java:822)
    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1060)
    at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
    at org.apache.catalina.core.StandardService.start(StandardService.java:525)
    at org.apache.catalina.core.StandardServer.start(StandardServer.java:759)
    at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
Caused by: java.lang.IllegalArgumentException: resource [spark-action-0.1.xsd] not found

这样,Oozie发送给JMS消息服务器的消息,在头部中都会带一个JobID了,而我们就根据这个JobID属性进行消息过滤。

可参考Oozie官方文档中给出的一句话:

JMS messages published are javax.jms.TextMessage . The body contains JSON and the header contains multiple properties that can be used as
 selectors. The header properties are not repeated in the body of the  message to keep the messages small.

由于JobID已经在body里面了,故Oozie并没有把它放到Header中去。

三,使用消息选择器来过滤消息

由于现在Oozie发送给ActiveMQ的每条JMS消息都会在头部带一个JobID,故现在可使用JobID作为消息选择器过滤消息了。

String selector=JMSHeaderConstants.JOBID + "='" + jobid + "'";
MessageConsumer consumer = session.createConsumer(topic, selector);

至此,就可以实现根据作业ID来接收该JobID所对应的作业的执行结果信息了。

Oozie JMS通知消息实现--根据作业ID来过滤消息的更多相关文章

  1. 解决 MySQL 比如我要拉取一个消息表中用户id为1的前10条最新数据

    我们都知道,各种主流的社交应用或者阅读应用,基本都有列表类视图,并且都有滑到底部加载更多这一功能, 对应后端就是分页拉取数据.好处不言而喻,一般来说,这些数据项都是按时间倒序排列的,用户只关心最新的动 ...

  2. [置顶] 手把手教你iOS消息推送证书生成以及Push消息

    iOS推送消息是许多iOS应用都具备的功能,今天在给应用加推送功能,在生成证书的过程中,发生了各种令人蛋痛的事.下面就把步骤拿出来分享下: iOS消息推送的工作机制可以简单的用下图来概括: Provi ...

  3. Windows消息理解(系统消息队列,进程消息队列,非队列消息)

    // ====================Windows消息分类==========================在Windows中,消息分为以下三类:标准消息——除WM_COMMAND之外,所 ...

  4. 【消息队列】kafka是如何保证消息不被重复消费的

    一.kafka自带的消费机制 kafka有个offset的概念,当每个消息被写进去后,都有一个offset,代表他的序号,然后consumer消费该数据之后,隔一段时间,会把自己消费过的消息的offs ...

  5. 分布式事务解决方案(二)消息系统避免分布式事务 & MQ事务消息 & Sagas 事务模型

    参考文档: 如何用消息系统避免分布式事务:http://blog.jobbole.com/89140/ https://www.cnblogs.com/savorboard/p/distributed ...

  6. ZeroMQ接口函数之 :zmq_msg_copy - 把一个消息的内容复制到另一个消息中

    ZeroMQ 官方地址 :http://api.zeromq.org/4-1:zmq_msg_copy zmq_msg_copy(3)   ØMQ Manual - ØMQ/3.2.5 Name zm ...

  7. Mina、Netty、Twisted一起学(二):TCP消息边界问题及按行分割消息

    在TCP连接开始到结束连接,之间可能会多次传输数据,也就是服务器和客户端之间可能会在连接过程中互相传输多条消息.理想状况是一方每发送一条消息,另一方就立即接收到一条,也就是一次write对应一次rea ...

  8. 【原创】源码角度分析Android的消息机制系列(一)——Android消息机制概述

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 1.为什么需要Android的消息机制 因为Android系统不允许在子线程中去访问UI,即Android系统不允许在子线程中更新UI. 为什 ...

  9. RabbitMQ 消息确认机制以及lazy queue+ disk消息持久化

    一:Basic的一些属性,一些方法 1. 消费端的确认 自动确认: message出队列的时候就自动确认[broke] basicget... 手工确认: message出队列之后,要应用程序自己去确 ...

随机推荐

  1. 【ntp】centos7下ntp服务器设置

    安装ntp #检查服务是否安装 rpm -q ntp #安装ntp服务器 yum -y install ntp 修改配置文件:/etc/ntp.conf 内容如下: restrict default ...

  2. 报错:Caused by: java.io.FileNotFoundException: d:\youTemprepository\upload_77faffc1_1580a9240ca__8000_00000001.tmp (系统找不到指定的路径。)

    org.apache.commons.fileupload.FileUploadBase$IOFileUploadException: Processing of multipart/form-dat ...

  3. sqlserver 登录失败——孤立用户

    USE (数据库实例)hhwz; GO sp_change_users_login @Action='update_one', @UserNamePattern='数据库用户', @LoginName ...

  4. 从IT匹配业务如何走向IT引领业务

    http://mp.weixin.qq.com/s?__biz=MjM5Njk2Mzg0MQ==&mid=200105892&idx=1&sn=cd9c155d09e8b975 ...

  5. PL/SQL中批量执行SQL脚本(不可把所有的语句都复制到New SQL Windows)

    PL/SQL中批量执行SQL脚本,不可把所有的语句都复制到New SQL Window,因为这样会导致缓冲区过大而进程卡死! 最好的办法是将要执行的SQL脚本存放到指定文件中,如C:\insert.s ...

  6. 正则表达式中的\b

    转自百度知道:https://zhidao.baidu.com/question/58688915.html\b表示的应该是ASCII码中的BS字符(退格字符),匹配字与字中间那个看不见的东西(即一个 ...

  7. nginx软负载的搭建

    Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器,在高连接并发的情况下Nginx 是 Apa ...

  8. python随文档

    UNIX网络编程--socket的keep http://www.68idc.cn/help/opersys/unixbsd/20150731471448.html 云计算学习和实践: 原创<每 ...

  9. PopuWindow_1

    PopupWindow有点类似于Dialog,相同点在于都是弹出窗口,并且都可以对其进行自定义显示,并且里面的监听组件,进行相应的操作, 但它与Dialog又有很大的区别,PopupWindow只是弹 ...

  10. 关于gcd函数解最大公约数

    数学知识:由于两个数的乘积等于这两个数的最大公约数与最小公倍数的积.即(a,b)×[a,b]=a×b.所以,求两个数的最小公倍数,就可以先求出它们的最大公约数,然后用上述公式求出它们的最小公倍数.例如 ...