如今应该所有ATM厂商的ATMC软件都是基于WOSA/XFS标准的了,即使不跨平台,各个厂商都会有自己的SP。
回过头想想我自己写的SP平台,还是有可以完善的地方,尤其是仔细的从业务的角度想想。
今天提到NCR关于流水的缓冲打印策略问题是因为其存在部分设计不完善。NCR的APTRA平台在通过XFS Manager的SPI接口调用打印机的PrintForm函数时,它在XFS Manager的上层有一个缓冲策略。也就是上层应用通过ActiveXFS发送一个流水打印命令,不是立即到SP层的,而是在ActiveXFS和XFS Manager之间有个缓冲模块,对打印进行排队。上层应用打印一条流水时,是一种异步调用,把打印内容放到缓冲模块的打印队列中就马上返回,不阻塞上层应用的下一步处理。具体的打印控制由该缓冲模块来调度。
这种类似的缓冲实现我们都很清楚,各个厂家都会做类似的工作。
但是NCR的缓冲有个小问题。这个需要我们来先看看其具体的过程。
假设有个客户做了一笔查询交易,应该打印的流水内容如下:
CardNo 0123456789123456
Accept Successful
Eject Card OK
一共三行,每行都是调用一个PrintForm的命令。考虑这种情况,上层应用很快的将这三行都放到缓冲队列中,然后缓冲队列开始打印。因为流水打印机一次只能打印一条记录,它是同步的,所以缓冲队列先打印第一条,等第一条打印完成再打第二条,依次类推。
NCR的策略是这样的,缓冲模块先调用SPI的打印命令打印第一条,因为可能因为硬件故障等原因导致该打印的SPI接口永远不会返回,所以每发送一个打印指令就会起一个定时器不断监测流水打印的状态是否为Busying状态,如果不是Busying,则表示SP已经将该条流水打印完成(这个是SP里面要求的);如果到了定时时间还是Busying,则表示设备可能有问题塞住了,如果还没到定时时间流水打印机SP就返回设备状态为OK,则表示本次打印已经完成。
再来看看什么时候将刚刚第一条流水从缓冲中删除,并不是在查询到流水打印机SP状态为OK后就删除,是等到PrintForm的那个完成事件到达时才删除的。
考虑这种情况,如果在状态为OK和PrintForm的那个完成事件到达之间有个时间差,而正好在这个时间差内定时器时间到了,则缓冲模块认为本次已经超时,其会取第二条缓冲队列数据来打印,而此时因为还没收到PrintForm的那个完成事件,缓冲队列第一条数据还没来得及删除,就会导致又将第一条流水内容又发给SP了。这样就导致将第一条流水重复打印两次。
再进一步考虑下,如果第二次将第一条流水很快打印出来,则缓冲模块会收到两个PrintFrom事件(刚刚第一次打印和第二次打印事件,虽然打印的内容是同样的,但事件是有两次)。如果简单的根据收到几次事件就将缓冲队列的前面几条数据删除进行处理,则会将队列中的第一条流水和第二条流水同时删除了,虽然第二条流水还没打印,根本不应该删除。这样就造成了漏打印第二条了。
所以最后的流水纸上可能打印的内容是
CardNo 0123456789123456
CardNo 0123456789123456
Eject Card OK
怎样处理才能避免呢?其实WOSA/XFS设计时是考虑了这种情况的。在每个命令和事件中都有个参数叫ReqID,即请求ID。每调用一个SPI,XFS Manager都会分配一个独一无二的ID号,表示该命令。利用ReqID,不要简单的根据收到了两次事件就将缓冲队列的两条记录删除,而是缓冲队列中要同时保存调用SPI时的ReqID,收到事件时要判断事件的返回参数里面的ReqID,只有与缓冲队列中相同时才会删除,不同的就不要删除,这样就避免了漏打的情况。
至于重复打印,可以将定时器的超时时间调大些,一般就会没问题了。
其实在WOSA/XFS里面提到的很多东西都是一笔带过,没有细讲,如果稍微不注意就会造成麻烦。
刘永胜 2005年于迪堡广州