为异步请求开发

您可以使用异步 API 命令来开发 CICS® 应用程序,以启动一个或多个子任务并从中访存响应。 当您开发用于异步 API 的应用程序时,将需要考虑异步 API 命令的流以及每个命令的可用选项。 如果要传递输入或接收响应作为异步请求的一部分,那么还必须考虑通道处理。

通过在 FETCH CHILDFETCH ANY 命令上使用 TIMEOUTNOSUSPEND 选项,您可以更好地控制父子行为,从而更轻松地使用异步应用程序来满足响应时间需求。

方案拟订方面的考虑和建议

以下是有关使用 CICS 异步 API 的一些实用指南和建议方法。 但是,您的环境和应用程序可能会有所不同,并从不同的方法中受益。 有关详情,请参阅 IBM® Redbooks® 刊物 IBM CICS 异步 API:并发处理变得简单

子任务应执行数据的 GET ,并将 UPDATE 留给父任务。
父任务和子任务是独立的工作单元 (UOW)。 例如,如果父代异常终止,那么它可以回退自己的工作,但将从子任务的执行中取消连接。 如果子任务仅限于 GET 操作,那么可以在不影响数据状态的情况下安全地废弃这些子任务。 子任务可以对数据执行 UPDATE。 但是,如果需要,您可能需要对补偿逻辑进行编码以还原更改。
允许同一父程序运行和访存子任务。
对于可管理性,开始子任务的父程序应保留从子任务访存结果的程序。 如果您使用的是 FETCH ANY 命令,那么此过程特别有用,因为如果 RUN TRANSIDFETCH ANY 命令位于不同的程序中,那么这些命令可能难以匹配。 另请注意,已访存的通道的作用域限定为链接级别。 因此如果不是家长访存孩子的结果,传递结果会有问题。
提示: 如果要从子任务检索响应数据,请在 EXEC CICS RUN TRANSID 中指定 CHANNEL ,即使您没有子任务的输入数据也是如此。
长时间运行的父代应使用 FREE CHILD 命令。
在长时间运行的父应用程序中,可以在子任务完成时构建控制块。 此外,还可以构建大量的通道数据。 如果没有任务终止,那么 CICS 系统无法安全地废弃此数据。 建议长时间运行的父任务删除任何访存的通道,并针对不再需要的子任务发出 FREE CHILD 命令。
跟踪访存的通道。
使用 CICS 通道和容器在父任务与子任务之间传递数据。 要从子代返回数据,子任务将更新其当前通道上的容器。 在子任务终止期间,通道由 CICS AS 域管理或拥有。 父任务可以通过在 FETCH CHILDFETCH ANY 命令上指定 CHANNEL 参数来检索子级通道。 这种方法比简单的查询更活跃。 通道将绑定到发出通知的父代。
查看 MAXTASK 并设置事务类。
异步 API 的简单性可能会在 CICS 系统中生成更多事务。 建议查看 MAXTASK 参数设置。 建议设置控件以限制区域接受的导致任务异步运行的工作量。
参数化超时。
在许多情况下,父代需要子代的结果来继续其业务逻辑。 如果需要超时,或者如果将来可能需要超时,那么可以对父代进行编码,以在 FETCH 命令上指定 TIMEOUT 参数。 超时的值应该参数化,例如从应用程序中较早的文件或数据库表中读取。 通过插入 TIMEOUT 参数并参数化 TIMEOUT 值,可防止将来需要更新或重新编译代码。
您可以在 FETCH CHILDFETCH ANY 命令上使用 TIMEOUTNOSUSPEND ,以提高应用程序通用性并满足各种情况下的业务需求:
  • 对于您肯定需要响应的任何子任务,请使用不带 TIMEOUTNOSUSPENDFETCH
  • 对于需要及时响应的子任务,请在 FETCH 命令上指定 TIMEOUT 值。
  • 对于不可接受响应的子任务,请在 FETCH 命令上指定 NOSUSPEND

示例

示例: 信用卡应用程序

在此示例中,将使用信用卡应用程序来演示如何使用这些命令。

启动信用检查子任务
  1. 将客户详细信息放入新渠道:
    EXEC CICS PUT CONTAINER('CUSTDETAILS') CHANNEL(customerDetails)
  2. 使用通道调用第一个信用检查服务:
    EXEC CICS RUN TRANSID('CRD1') CHILD(creditCheck1_tkn) CHANNEL(customerDetails)
  3. 使用同一通道调用第二个信用检查服务:
    EXEC CICS RUN TRANSID('CRD2') CHILD(creditCheck2_tkn) CHANNEL(customerDetails)

父程序可以在发出 EXEC CICS RUN TRANSID 命令之后继续进行其他处理,并且可以在之后的任何时候发出 EXEC CICS FETCH 命令以检索子任务的结果。

从特定子任务获取响应
  1. 从第一个子代访存响应:
    
    EXEC CICS FETCH CHILD(creditCheck1_tkn) CHANNEL(credReply1_chan) 
              COMPSTATUS(credReply1_status)

    在这种情况下,将阻止父处理,直到子任务返回结果为止。 使用可选参数 NOSUSPENDTIMEOUT 可防止或限制作为首选的分块。

  2. 检查 EXEC CICS FETCH CHILD 命令的响应代码以确保命令正常执行。
  3. 如果 EXEC CICS FETCH CHILD 命令正常执行,请检查子代的 COMPSTATUS 以确保其成功完成。
    • 如果 COMPSTATUS 指示子任务已成功完成,请从应答通道获取响应。
      EXEC CICS GET CONTAINER('RESULT') CHANNEL(credReply1_chan)
    • 如果 COMPSTATUS 指示子任务异常终止,那么父应用程序的逻辑应决定要执行的操作。 当父事务完成时, CICS 将清除所有资源。
  4. 对第二个子任务重复步骤 1 到 3。
从任何已完成的子任务获取响应

还可以使用 EXEC CICS FETCH ANY 命令从任何已完成的子任务访存响应,这将返回先完成的任何子任务的结果:


EXEC CICS FETCH ANY(creditCheck_tkn) CHANNEL(credReply_chan) 
          COMPSTATUS(credReply_status)

检查 FETCH ANY 命令的完成情况以及子代的 COMPSTATUS 是否正常。

释放儿童

作为父任务的一部分,您可以选择释放子任务,这将整理相关联的资源并使系统存储器使用率降至最低,这对于长时间运行的父任务尤其有用。 例如,如果启动了三个子任务,但只需要一个子任务的结果,那么可以使用 FREE CHILD来清除其余两个子任务。


EXEC CICS FREE CHILD(creditCheck1_tkn)
EXEC CICS FREE CHILD(creditCheck2_tkn)
表 1. 参考: 可选参数
命令 可选参数 用法
EXEC CICS RUN TRANSID CHANNEL 将其用于:
  • 将数据传递给子代。
  • 从子级接收数据。
  • 在子级之间传递和接收数据。
RESP 使用它来查看是否成功执行了命令
EXEC CICS FETCH 命令 CHANNEL 使用它从子任务接收数据,只要在初始 RUN TRANSID 命令上提供了通道。
暂停 使用它来阻止 FETCH 命令: 无论子任务是否已完成,该命令都将立即返回。

如果发出该命令时子任务已完成,那么该命令将立即返回 NORMAL 响应。 如果子代尚未完成,那么将发生NOT制成品条件, RESP2 值为 52。

超时 使用它可使 FETCH 命令在返回前等待指定的时间量。

您可以指定父任务将等待子任务完成的最长时间 (以毫秒计)。 当使用非零值指定 TIMEOUT 时,父任务将不受 DTIMOUT约束。

如果子任务在到达 TIMEOUT 之前完成,那么命令将立即返回。 如果在达到 TIMEOUT 之前子任务尚未完成,那么将出现值为 53 的 RESP2 的NOT已完成条件。

ABCODE 如果 COMPSTATUS 指示子代已异常终止,那么 ABCODE 将包含子代的异常终止代码。

示例: 将子令牌传递到链接的程序以访存来自子任务的响应

以下步骤是如何使用通道在父任务和子任务之间传递输入和输出的示例。

  1. 父任务 PROGP1将输入传递到通道中的子任务,然后将其链接到本地程序 PROGP2
    
    EXEC CICS PUT CONTAINER('REQ') FROM(REQUEST) CHANNEL('ASYNC-CHANNEL')
    EXEC CICS RUN TRANSID('CHLD') CHANNEL('ASYNC-CHANNEL') CHILD(CHILD-TOKEN)
    EXEC CICS PUT CONTAINER('CHILDTOKEN')  FROM(CHILD-TOKEN) CHANNEL('ASYNC-CHANNEL')
    EXEC CICS LINK PROGRAM('PROGP2') CHANNEL('ASYNC-CHANNEL')

    父代创建的 ASYNC-CHANNEL 的副本将传递给子代,并且该副本将成为子代的初始程序的当前通道。 通道的名称由复制过程保留,因此如果子程序 PROGC1 发出 EXEC CICS ASSIGN CHANNEL ,那么将返回 ASYNC-CHANNEL

  2. 事务标识为 CHLD 且程序为 PROGC1的子任务从其当前通道获取输入:
    EXEC CICS GET CONTAINER('REQ')

    然后,子代将继续其逻辑,为父任务生成响应,然后将其放入其当前通道内的容器中:

    
    EXEC CICS PUT CONTAINER('RESP') FROM(RESPONSE)
    EXEC CICS RETURN
  3. 父任务 PROGP2将访存子响应并继续执行某些业务逻辑,然后返回到 PROGP1:
    
    EXEC CICS GET CONTAINER ('CHILDTOKEN') INTO(CHILD-TOKEN)
    EXEC CICS FETCH CHILD(CHILD-TOKEN) CHANNEL (FETCHED-CHANNEL)
    EXEC CICS GET CONTAINER('RESP') CHANNEL(FETCHED-CHANNEL)

    当父任务从子代访存响应通道时, CICS 会生成唯一的通道名称,并将该通道绑定到当前程序链接级别。 在此示例中,访存的通道将由 PROGP2拥有。 当 PROGP2 返回到 PROGP1时, CICS将删除访存的通道。 子响应通道只能由父任务访存一次。

示例: CICS 异步 API 访存变体

开始之前本示例的源代码全文可在 GitHub 上还可以找到设置和运行说明。

此 COBOL 示例有一个父程序 ASYNCPG1 ,用于演示 EXEC CICS FETCH 带有和不带有选项 TIMEOUTNOSUSPEND 的命令。 该应用程序还有四个子程序: ASYNCCH1, ASYNCCH2, ASYNCCH3, ASYNCCH4。

ASYNCPG1 启动四个异步子任务。 然后,根据业务需求执行 3 不同类型的访存以获取响应,如下所示:
  • 父程序需要来自第一个子代的响应,因此请使用不带 SUSPENDTIMEOUT 选项的 FETCH CHILD
    
    EXEC CICS FETCH CHILD(CHLDTOKN1) CHANNEL(CHLDCHNL1)
               COMPSTATUS(CVDA)
               RESP(W-RESP) RESP2(W-RESP2)
               END-EXEC.
  • 在访存来自第二个子代的响应时,父程序最多可以等待 1000 毫秒,因此请使用 FETCH CHILD TIMEOUT
    
    EXEC CICS FETCH CHILD(CHLDTOKN2) CHANNEL(CHLDCHNL2)
               TIMEOUT(TIMEOUT1)
               COMPSTATUS(CVDA)
               RESP(W-RESP) RESP2(W-RESP2)
               END-EXEC.
    其中 TIMEOUT1 定义如下所示,可以在程序中动态更改,也可以通过从文件或数据库中读取以适合您的环境:
    01 TIMEOUT1     PIC S9(8) USAGE BINARY VALUE 1000.
  • 对于第三个和第四个子代,父程序可能有任何结果,但无法等待,因此请使用 FETCH CHILD NOSUSPEND
    
    EXEC CICS FETCH ANY(ANYTOKN) CHANNEL(ANYCHNL)
               NOSUSPEND COMPSTATUS(CVDA)
               RESP(W-RESP) RESP2(W-RESP2)
               END-EXEC.