全部博文(56)
分类: Java
2011-07-28 16:57:41
在批量应用的开发环境下出现以下现象。2009年2月6-2月9号对跨行支付应用“XXXX处理流程”进行版本验证时,发现工作流程运行到“发送对帐文件” 作业单元时就结束了,并没有运行到工作流的“结束”活动。经公司支持工程师问题排查,其流程在执行到该作业单元时,shell业务脚本返回非分支条件内的逻辑结果,导致流程运行到该作业单元后便正常的结束了流程。其中批量“发送对帐文件”作业单元调度了Shell脚本,Shell脚本中调用了C开发的应用程序,经现场分析初步判断为系统环境、C应用程序、Shell脚本及操作自动化产品平台在进行的连接调试的过程中出现了非预期的结果。
经公司现场工程师支持及我行开发部人员分析。其中珠海开发中心“跨行支付”中的“大额日终处理流程”工作流“发送对账文件请求”作业单元是引起问题的作业单元。其工作原理是由产品的ShellCmd作业单元调度Aix5.3环境下的shell脚本;其shell脚本中调用C语言程序编译的原程序,通过整体配合完成批量作业的业务执行。作业流程通过su - ibps entegorsh/ibps_clifix.sh命令,以切换用户的方式进行脚本调用,在调用并执行完shell脚本后,shellcmd作业单元得到脚本返回结果“stdout”、“lastLine”及“stderr”三个属性值皆为空,即shellcmd作业单元没有接收到shell脚本的输出返回,工作流便正常执行结束。
(注:当前手工执行Shell脚本是可以执行批量业务。同时在solaris环境下,通过操作自动化平台进行调度,也可以正常执行批量业务。在Aix3.5环境下调度会出现以上现象。)
为了迅速排查问题,我行开放平台项目组积极协调我司进行快速响应。我司工程师XXX于2月13日迅速赶赴珠海开发中心,并于2月14日抵达现场开展了支持工作。并积极配合于XXX工程师对该问题进行了排查与分析。分析的结果如下:
环境描述1、 操作自动化系统引擎服务部署在windows平台下。
2、 操作自动化系统Agent服务部署在AIX5.3平台下。
3、 Shell脚本与C程序及函数库都部署在远程AIX5.3操作系统下。
4、 Agent服务的启动用户为Root用户。
5、 AIX5.3系统的脚本执行用户为ibps用户。
测试步骤描述1、 手工调用调试
在远程控制台上,使用命令“su - ibps entegorsh/ibps_clifix.sh”,其中 ibps为用户名,entegorsh/ibps_clifix.sh为执行shell脚本。其中批量业务Shell脚本手工执行的情况下,可正常运行并打印出完整提示信息。
2、 Entegor平台调用调试
使用Entegor平台的studio工具,定制新工作流rensijiang_test, 该工作流中只包含一个shellcmd作业单元,在Shellcmd活动的“命令行”配置为“su – ibps /shell脚本路径/shell脚本名称”,在该活动中的“高级设置”中配置该活动在远程Agent上执行,配置远程Agent的IP为shell脚本所在的机器的IP,agent的启动用户为root。工作流运行完成,shellcmd活动的“stdout”、“lastLine”及“stderr”三个属性的值皆为空。
3、 C语言脚本排查
经过对C语言脚本的分段注释排查,发现当将C语言脚本的块代码如下:
if(atol(retcode) == 0 && atol(pubretcode)==0) { sprintf(errmsg,"发送659报文成功!"); //printf("%s\n", errmsg); ibpslog( __FUNC__ , errmsg); retflag=0; } else { sprintf(errmsg,"发送659报文失败! retcode=[%s], retmsg=[%s]", retcode, retmsg); //printf("%s\n", errmsg); ibpslog( __FUNC__ , errmsg); retflag=-1; }
|
通过本段代码注释后,shellcmd即可获得C语言程序及shell脚本的输出,且业务执行正常。经过对该段代码的进一步排查发现,是因为C文件中的:printf("%s\n", errmsg);语句,导致shellcmd活动不能接收到C语言与shell脚本的输出信息。
4、 调试分析
对该语句进一步分析,发现printf函数在打印errmsg变量时,shellcmd活动无法接到C程序与shell脚本的输出信息。将该变量修改为字符串(例如:"发送659报文失败"),shellcmd活动可以接收到C语言与shell脚本的输出。
if(atol(retcode) == 0 && atol(pubretcode)==0) { sprintf(errmsg,"发送659报文成功!"); //printf("%s\n", errmsg); ibpslog( __FUNC__ , errmsg); retflag=0; } else { sprintf(errmsg,"发送659报文失败! retcode=[%s], retmsg=[%s]", retcode, retmsg); printf("%s\n", errmsg); ibpslog( __FUNC__ , errmsg); retflag=-1; } |
经以上代码块注释后,shellcmd即可获得C语言程序及shell脚本的输出,且业务执行正常。经过对该段代码的进一步排查分析发现,是C文件中的:printf("%s\n", errmsg);语句导致的问题。使C语言与shell脚本的输出信息不能反馈回自动化平台的shellcmd作业单元。
我司提出一下思路来解决跨行支付应用中出现的问题。在Aix系统环境下,针对跨行支付应用的“发送对帐文件”单元,其C应用函数printf()函数打印char类型数组变量时,会导致C语言与shell脚本的输出信息不能反馈回自动化平台的shellcmd作业单元,具体根源由我司工程师任思江继续在现场进行跟踪分析。
针对该问题,可通过以下方式进行调试解决。
建议一,通过调整C脚本语句进行解决。将原代码调整如下:
源代码 |
修改后的代码 |
sprintf(errmsg, "创建xml树失败"); printf("%s\n", errmsg); |
sprintf(errmsg, "创建xml树失败");
|
通过printf();语句直接输出字符串提示信息,而非通过打印errmsg字符串数组的方式进行控制台输出。
建议二,在打印输出前,先对内存变量(例如:errmsg变量)的内存空间进行清理,在打印输出。
源代码 |
修改后的代码 |
sprintf(errmsg, "创建xml树失败"); printf("%s\n", errmsg);
其次例如以下的代码,在使用retmsg变量的时候也需要初始化: sprintf(errmsg,"发送659报文失败! retcode=[%s], retmsg=[%s]", retcode, retmsg); printf("%s\n", errmsg); ibpslog( __FUNC__ , errmsg); retflag=-1; |
memset(errmsg, 0x00, sizeof(errmsg));//清理 sprintf(errmsg, "创建xml树失败"); printf("%s\n", errmsg); memset(retmsg, 0x00, sizeof(retmsg));//清理,使用retmsg变量时也需要先初始化。
|
建议三,申请变量(例如:errmsg变量)的内存空间限定在1004字节范围内。
源代码 |
修改后的代码 |
sprintf(errmsg, "创建xml树失败"); printf("%s\n", errmsg); |
char errmsg[1003+1];//声明 sprintf(errmsg, "创建xml树失败"); printf("%s\n", errmsg); |
通过以上三种方式的任何一种修改,都可完成当前应用问题的规避。