Cordys(C3)工作流办结流程数据迁移清理方案及实践

1、概述

1.1、关于工作流数据

        提到工作流数据,就不得不提业务数据。作为最直接的区分,我们将存储于业务系统中的数据称为业务数据,将存储于工作流系统中的数据称为工作流数据。根据 WFMC 定义,我们将工作流数据分为工作流控制数据和工作流相关数据。

        1、  工作流控制数据 。指被工作流系统管理的系统数据,这些数据包括了与流程实例和任务实例相关的执行数据,例如流程实例的状态、执行时间等信息、任务实例的执行者、执行时间、状态、紧急程度等。

        2、  工作流相关数据 。指与业务流程相关的数据。工作流相关数据又具体分为 3 种:

  • 影响流程实例执行的业务数据。在 WFMC 中, 这个数据被描述为:工作流系统通过该数据来确定流程实例的流转条件,并选择下一个将执行的任务,这些数据可以被业务系统访问并修改。例如报销流程中的“报 销金额”,这个数据会决定该流程的审批路径;再例如为任务设置的超时时间,这个数据会触发任务的取消。实质上这些数据就是工作流系统需要依赖于进行流程流 转的业务数据。
  • 契合业务的关联数据。指工作流系统与业务系统进行关联的数据,例如特定于 WEB 系统,工作流系统会在每个流程实例里保持有导航至对应业务表单的 URL 。
  • 传递作用的业务数据。当流程跨越多个业务模块时,需要在模块间传递数据,此时会利用工作流系统进行传递,会在工作流系统里暂时存储这些业务数据。

1.2、关于基于Cordys平台的办公系统

        办公系统是基于SOA和BPM技术架构,采用Cordys平台建设的信息系统,数据库为Oracle,实现了办公业务集中化、全面化管理,初步达到集中办公平台的目的,系统主要包括公文管理、通用办公、专业流程、综合信息、专业办公五大子系统。

         在此工作流数据有哪些应用场景呢?

  • 首先,在系统建设时,为了快速开发,系统设计时,工作流数据与业务数据耦合较多,也就是说工作流数据与业务系统集成在一起,虽然如此,但是很多数据在流程结束后,是可以剥离。
  • 其次,虽然很多工作流产品都提供了办结流程数据解决方案,例如按时间迁移清理历史数据。而在实际业务系统建设、使用过程中,个性化需求驱动下,产品所提供的功能往往失效,例如:例如主流程下涵盖子流程,在子流程结束时,而主流程可能没有结束,而从流程实例角度来说,某个子流程已经结束。

        办公系统已经上线使用4年多了,其中某流程处理数据表(process_activity)的记录已经有5千多万条,其中在两年前处理过,并迁移走近2千万条,实践证明此处理方案有效,对业务影响可以忽略,特殊情况人工处理就可以。

2、Cordys工作流相关主要表及解决方案

2.1、Cordys核心表及相关业务表

Cordys(C3)工作流办结流程数据迁移清理方案及实践_第1张图片


        如上图所示,表的情况如下:


序号

表名

功能介绍

1

Process_instance

流程实例

2

process_activity

流程实例处理活动

3

MESSAGE_TRACK

流程实例处理消息活动

4

MESSAGE

流程实例处理消息

5

NOTIFICTION_SEARCH_DATA

 

6

TASK_LIST

待办任务处理活动(业务)

7

WORKFLOW_INSTANCE_TRANSLOG

流程流转记录(业务)

8

PROCESS_INSTANCE_DATA

在途流程实例(未办结流程实例)


        上表中,Cordys流程核心表有Process_instance、process_activity、MESSAGE_TRACK、MESSAGE、NOTIFICTION_SEARCH_DATA、PROCESS_INSTANCE_DATA,其中PROCESS_INSTANCE_DATA是在途流程信息,不需要清理,其他的需要适当的情况,而业务表的TASK_LIST中数据,办结流程的任务迁移到task_list_finished表中,表结构完全一致。

2.2、清理迁移数据解决方案

        流程办结数据与在途数据,经过对比分析,最多记录表process_activity表的在途记录数也不过百万级别,而办结数据已经3千多万,因此处理方案的基本原理是:

  • 现有的待处理的Cordys核心表更名为备份表,保证数据不丢失;
  • 重建Cordys待处理核心表,新建表时索引、主键先不建,等数据处理后再建;
  • 依据未办结业务数据的流程实例信息,导数据插入对应的新建的表中;
  • 系统恢复运行3~6个月后,根据存储空间情况,自行删除已经成为历史数据的表。

2.2.1、Cordys核心表处理过程

          由于PROCESS_INSTANCE_DATA表是在途流程实例,不需要进行处理。

Cordys(C3)工作流办结流程数据迁移清理方案及实践_第2张图片


2.2.2、关于办结流程的识别

        办结流程可以根据ApptoolKit中workflow_instance表来识别(例如:STATUS = 'COMPLETE'),同时,还需要识别其中的子流程,以及嵌套子流程(例如:通过PARENT_GUID和GUID两个字段来进行识别),识别出三级嵌套就足够了,再特殊的,人工处理。

Cordys(C3)工作流办结流程数据迁移清理方案及实践_第3张图片

        把识别出来的办结流程标识,去重后放置在临时表中,后续使用。

2.2.3、任务表数据清理迁移方案

        任务表(task_list)主要是存储在办和办结任务数据,办结任务数据要定期迁移到办结任务表中(task_list_finish)。

Cordys(C3)工作流办结流程数据迁移清理方案及实践_第4张图片

        任务表task_list是分区表,为了快速插入数据,在执行插入操作时,一般就逐个分区进行插入操作。

2.2.4、存储表空间回收处理方案

        由于Cordys核心表用到LOB字段,用于存储XML格式数据,这样将占有大量磁盘空间(按现有业务量估算,3年预计为1T),因此,在删除表的时候,最好也移除表空间。

Cordys(C3)工作流办结流程数据迁移清理方案及实践_第5张图片


3、数据迁移清理实践

3.1、数据处理全过程概述

        1、策划分析阶段工作

        全面获取存储、表空间使用情况,以及相关表数据量,并通过查询等多种模式模拟数据处理过程及所消耗的时间,并据此预估数据处理停业时间,制定作业计划。

        导出建表、索引SQL语句(因为系统在运维过程中,可能要发生微小的改变,因此,每次都要重新生产SQL脚本)。

        2、发通知,停业,停应用服务

        3、表更名、索引更名

        4、新建表,处理数据

        根据实际情况,如有必要则新建表空间,把表建到新表空间上。

        5、重建索引、存储过程、触发器等

        按事先准备好的脚本执行。

        6、启动应用服务,检查平台

        7、测试流程相关应用,并处理问题

        8、清理测试数据

        9、恢复业务。

3.2、关键过程案例

3.2.1、表更名

--修改表名
alter table notification_search_data rename to bak_notification_search_data;
alter table message_track rename to bak2011_message_track;
alter table message rename to bak2011_message;
alter table process_activity rename to bak2011_process_activity;
alter table process_instance_data rename to bak2011_process_instance_data;
alter table process_instance rename to bak2011_process_instance;
alter table workflow_instance rename to bak2011_workflow_instance;
alter table workflow_instance_translog rename to bak_workflow_instance_translog;

--修改约束
alter table MESSAGE rename constraint MESSAGEPKEY to MESSAGEPKEYtmp;
alter table MESSAGE_TRACK rename constraint MESSAGETRACKPKEY to MESSAGETRACKPKEYtmp;
alter table PROCESS_ACTIVITY rename constraint SYS_C006752 to SYS_C006752tmp;

--修改索引

alter index IX_PROCESS_INSTANCE_START_TIME rename to IX_PROCESS_INSTANCE_STARTtmp;
alter index IX_PROCESS_NAME rename to IX_PROCESS_NAMEtmp;
alter index IX_PROCESS_INSTANCE_END_TIME rename to IX_PROCESS_INSTANCE_END_Ttmp;
alter index SYS_C006752 rename to SYS_C006752tmp;

      修改时,最好先修改索引、约束,最后修改表名。

3.2.2、处理工作流数据

        使用存储过程处理数据,最少分成两个阶段,第一阶段处理流程实例数据,根据处理结果,提取流程消息数据,再进行第二阶段流程消息数据处理,由于插入数据时,表不适宜建索引,所以在process_activity数据处理完成后,为此表建主键、索引,才方便提取消息message_id。

      select distinct t.message_id
          from cordys.process_activity t
          where not exists (select t1.message_id    from cordys.message t1   where t1.message_id = t.message_id);


1、处理流程实例数据

create or replace procedure pro_data_new1 is
  --游标,取出待处理的办结流程guid
  cursor wait_worklow_instance is
    select t.workflow_instance, t.process_instance  from wait_worklow_instance_temp t  where t.process_instance is not null
       and not exists (select t1.guid   from cordys.workflow_instance t1  where t1.guid = t.workflow_instance);

  v_instance_count number(9);
  v_num            number(9); --提交计数
  v_sqlcode        number;
  v_sqlmsg         varchar2(2000);

  v_instance_guid    cordys.workflow_instance.guid%type;
  v_process_instance cordys.workflow_instance.process_instance%type;
  v_log_id           number;

begin
  v_instance_count := 0;
  v_num            := 0;
  v_log_id         := 0;


  select count(*) into v_log_id from tmp_workflow_data_log;
  if v_log_id > 0 then
     select max(id) into v_log_id from tmp_workflow_data_log;
  end if;

  v_log_id := v_log_id + 1;

  insert into tmp_workflow_data_log(id,state,logdate)    values(v_log_id,'Start Test!',sysdate);

  open wait_worklow_instance;
  loop
    fetch wait_worklow_instance   into v_instance_guid, v_process_instance;
    exit when wait_worklow_instance%notfound;


    select count(*)
      into v_instance_count    from cordys.bak2011_workflow_instance   where guid = v_instance_guid;
    if v_instance_count > 0 then
      --迁移流程实例数据
      insert into cordys.process_instance
        select *   from cordys.bak2011_process_instance  where instance_id = v_process_instance;
      --迁移流程活动数据
      insert into cordys.process_activity
        select *  from cordys.bak2011_process_activity  where instance_id = v_process_instance;
    end if;


    if v_num > 1000 then
      v_log_id := v_log_id + 1;
      insert into tmp_workflow_data_log(id,state,logdate)  values(v_log_id,'insert 1001 record workflow',sysdate);
      commit;
      v_num := 0;
    else
      v_num := v_num + 1;
    end if;
  end loop;

  v_log_id := v_log_id + 1;
  insert into tmp_workflow_data_log(id,state,logdate)   values(v_log_id,'insert workflow data complete',sysdate);

  commit;
  close wait_worklow_instance;

  commit;
exception
  when others then
    v_sqlcode := sqlcode;
    v_sqlmsg  := substr(sqlerrm, 1, 2000);
    dbms_output.put_line(v_sqlcode || '::' || v_sqlmsg);
end;
--其中,每千条数据提交一次,为了是数据处理稳定,并根据日志监控进程。


2、处理流程消息数据

create or replace procedure pro_data_new2 is
  --注意:process_instance流程实例为空的滤除
  cursor tmp_message is
    select distinct t.message_id   from cordys.tmp_message_id_201112 t
     where not exists (select t1.message_id    from cordys.message t1   where t1.message_id = t.message_id);

  v_instance_count number(9);
  v_num            number(9); --提交计数
  v_sqlcode        number;
  v_sqlmsg         varchar2(2000);


  v_instance_guid    cordys.workflow_instance.guid%type;
  v_process_instance cordys.workflow_instance.process_instance%type;
  v_message_id       cordys.message.message_id%type;
  v_log_id           number;

begin
  v_instance_count := 0;
  v_num            := 0;
  v_log_id         := 0;

  select count(*) into v_log_id from tmp_workflow_data_log;
  if v_log_id > 0 then
     select max(id) into v_log_id from tmp_workflow_data_log;
  end if;

  v_log_id := v_log_id + 1;

  insert into tmp_workflow_data_log(id,state,logdate)   values(v_log_id,'Start Test!',sysdate);

  v_num := 0;
  open tmp_message;
  loop
    fetch tmp_message
      into v_message_id;
    exit when tmp_message%notfound;
    --迁移消息数据表
    insert into cordys.message   select * from cordys.bak2011_message where message_id = v_message_id;
    --迁移消息跟踪数据表
    insert into cordys.message_track
      select *  from cordys.bak2011_message_track   where message_id = v_message_id;
    --迁移消息通知数据表
    insert into cordys.notification_search_data
      select *  from cordys.bak_notification_search_data   where message_id = v_message_id;
    if v_num > 1000 then
       v_log_id := v_log_id + 1;
       insert into tmp_workflow_data_log(id,state,logdate)    values(v_log_id,'insert 1001 record message',sysdate);
      commit;
      v_num := 0;
    else
      v_num := v_num + 1;
    end if;

  end loop;
  close tmp_message;
  v_log_id := v_log_id + 1;
  insert into tmp_workflow_data_log(id,state,logdate)
    values(v_log_id,'insert message data complete',sysdate);
  commit;
  
exception
  when others then
    v_sqlcode := sqlcode;
    v_sqlmsg  := substr(sqlerrm, 1, 2000);
    dbms_output.put_line(v_sqlcode || '::' || v_sqlmsg);
end;

3.3、其它注意事项

        1、手工恢复触发器

        触发器、Sequence是最容易忽略、出问题的地方,因为在表更名时,对应的代码可能发生改变,一定要注意核对。
        AFTER_INSERT_MESSAGE_TRACK
        AFTER_UPDATE_MESSAGE_TRACK
        AFTER_UPDATE_PROCESS_INSTANCE

        2、异常数据永远是存在的,只能人工分析进行处理,如果一个流程跑3个月了,是因为异常数据,估计这个流程实例也就是个作废的流程实例;

        3、任务数据处理

        把办结任务数据task_list(备份表)导入到办结任务数据表(task_list_finish)中时,如果遇到长时间未清理数据,或者说数据量较大时,最好也编写存储过程批量导入到办结表中。

4、总结

        本文处理方案和实施,是从2011年11月开始,中间经过2012年、2013年不断改进、优化,处理数据的方案和技术相对较成熟了,但整个系统的业务功能和数据增涨是常态,所以,处理历史数据的方案也要继续优化。 

        本文所描述的历史数据处理方案、思想可以推广到其他系统,而处理数据如此麻烦,也和最初设计有不合理的地方有关,设计人员可以从中汲取些经验教训,有遗漏、不完善的后续完善。

        欢迎同行多交流。


参考:

ronghao100 ,浅谈工作流数据 , http://blog.csdn.net/ronghao100/article/details/5625120

Oracle中查询索引名称,批量修改索引名称语句 , http://blog.csdn.net/xiaoyw71/article/details/15338405

关于Cordys平台办结流程数据管理方案 , http://blog.csdn.net/xiaoyw71/article/details/15338391

基于Cordys平台上的待办任务优化改造方案 , http://blog.csdn.net/xiaoyw71/article/details/15338373


你可能感兴趣的:(业务流程,IT运维管理)