SEMQ的一个不符合时序控制的传输现象

零售商端tb_0031中具有相同时序控制键(f023v_0031)的单据消息(可能是按每一部分包含一张单据的不同明细抽取的,并指定以增量修改方式处理),发送状态全部为SS_ACK(6).
时序控制的核心逻辑是:端-端确认,具有相同时序键的消息只有在上一个消息确认送达(SS_ACK2=100)后才能发送下一个消息.

这个现象应该隐藏着一个bug.

SEMQ队列元素的发送状态定义如下:

 enum {
  SS_UNSEND=0, ///< 未发送
  SS_SEND = 4, ///< 已发送
  SS_FWD = 5, ///< 已转发
  SS_ACK = 6, ///< 已送出
  SS_SUSPEND = 10,///人工挂起 
  SS_SUSPEND2= 12,///自动挂起 
  SS_ABANDON=15,///放弃 
  SS_ACK2 = 100 ///< 已送达
 }; 

 

各种状态解释如下:

SS_UNSEND:未发送,进入发送队列
SS_SEND表示应用进程尝试了发送,只是进入内存中的待发送任务队列中,甚至可能没有执行网络层的发送.

SS_ACK:目标或中转返回的确认消息

SS_ACK2:目标方的接受确认

SS_SUSPEND,SS_SUSPEND2,SS_ABANDON保留.


相同时序键的多条单据消息,在发送端的发送状态都是SS_ACK.这是非预期的情况.
按设计逻辑,这些消息应当串行地改变,只有上一条消息(相同时序键的消息按object_id升序排序)变成SS_ACK2后,下一消息才开始发送.

808-MT_INDICATION处理

int CBBoxPlugin::OnInquiry2(CWrappedMsg<> *in,vector<CWrappedMsg<> *> &out,DISPATCH_RESULT &or) {
  ...
  unsigned short status = ISEMQ::SS_ACK2;
  if(src_t == PT_CENTRAL && qe.dest_type_ != PT_CENTRAL)
   status = ISEMQ::SS_ACK;
  ...
}   


目标为平台的消息的最终状态ISEMQ::SS_ACK.
***应该统一状态图.
中转节点只负责执行一次发送,发送状态为SS_SEND就不再处理了.后续由发送端检查和控制.

以下代码应该是可以消除的:

  if(src_t == PT_CENTRAL && qe.dest_type_ != PT_CENTRAL)
   status = ISEMQ::SS_ACK;
   
810-MT_CONFIRMATION处理
int CBBoxPlugin::OnAck(CWrappedMsg<> *in,vector<CWrappedMsg<> *> &out,DISPATCH_RESULT &or) 
   ///< 发送给PT_APP的消息,只要已到达平台(写入网关应用队列),就算已经送达
   ///< 如果确认消息来自平台,但是队列记录的目标不是平台,表示可能并没有发送到目标方(非平台)
   if(src_t == PT_CENTRAL && qe.dest_type_ != PT_CENTRAL && qe.dest_type_!=PT_PAPP){ \
    status = ISEMQ::SS_ACK;
   }
   else {
    status = ISEMQ::SS_ACK2;
   }

   
   GETDBC_RETURN(pdbor,this->local_dbc_.c_str(),-1);
   pdbor->BeginTrans();
   if (semq_.UpdateStatus(ssr.record_id_,status)) {
    pdbor->RollbackTrans();
    return -2;
   }
   ///< 如果目标是平台(且status==6)或者已送达,该确认的是有时序控制的记录,则取下一条
   if ((qe.dest_type_==PT_CENTRAL||status==ISEMQ::SS_ACK2)&&!qe.sc_key_.empty()) {
    CQQ_OBJECT_ID next_object_id=qe.object_id_;
    int ret = semq_.GetNextSeqCtrlRecord(qe.sc_key_.c_str(),next_object_id);
    if (ret==1) {
     pdbor->SetTXHook(TxHook,&semq_);
     semq_tss_->v_rec.push_back(new SEMQ_RECORD_DATA_PAIR(next_object_id, qe.sc_key_));
    }
    else if (ret==-1) {
     pdbor->RollbackTrans();
     return -3;
    }
   }
   
发送状态改变:

确认消息的发送端是待发送消息的目标时表示已经送达(判定条件为:src_t==qe.dest_type&&src_id==qe.dest_id_)
    status = ISEMQ::SS_ACK2;
否则,只表示已经被中转节点(如平台)存储或者转发(目前没有细分这2种情况,由于目标不在线,平台存储后返回一个确认消息)   
    status = ISEMQ::SS_ACK; 
    
目前的判定条件    
   if(src_t == PT_CENTRAL && qe.dest_type_ != PT_CENTRAL && qe.dest_type_!=PT_PAPP){
存在问题:
 .逻辑不严谨:未比较端点类型
 .PT_CENTRAL,PT_PAPP特殊处理:这种特殊处理是不必要的,除非这些端点没有遵循统一的传输确认机制.
 ---考虑影响面大,测试量大,完善这种问题需要等待合适的时机.
 
CSEMQ::GetData
   
int CSEMQ::GetData(string &sql)
发送时进行时序控制.

f017c_0031标志
f017c_0031被定义为确认标志,几经版本变化,现在已经没有意义不需要了. (一旦修改semq中使用f017c_0031的代码后需要对整体分布式通信环境测试)
f016c_0031可以区分可靠性级别和相应的传输确认机制.不再需要f017c_0031.
废除f017c_0031可简化逻辑,提高性能.如问询和时序控制条件:

 inquiry_expr_ = "((f016c_0031=3 and f009n_0031=4) or (f017c_0031=1 and f009n_0031=6))"; ///< f017c_0031=1实际上包含了f016c_0031(必须为3)
 seqctrl_expr_ = "((f016c_0031=3 and f009n_0031 in (4,10,12)) or (f017c_0031=1 and f009n_0031=6))";  ///< 时序控制时判定是否还有未处理的先前记录的过滤条件(如一张单据的2次改变产生的2条记录,第1条未确认则后面的不发送)

 

处理:问题待测试和定位
.专门针对此现象进行测试:发送方tb_0031中2条相同f023v_0031的记录,设置f009n_0031=0.目标机构服务器不在线.发送方处理后检查这2条记录的发送状态(f009n_0031).
.SEMQ可优化

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值