Developing for asynchronous requests

You can develop a CICS® application using the asynchronous API commands to start one or more child tasks and fetch responses from them. When you develop applications for use with the asynchronous API, you will need to consider the flow of the asynchronous API commands and the available options for each command. Channel handling must also be considered if you want to pass input or receive responses as part of an asynchronous request.

Using the TIMEOUT and NOSUSPEND options on the FETCH CHILD and FETCH ANY commands, you have more control over parent-child behavior, making it even easier to reach response time requirements with asynchronous applications.

Programming considerations and recommendations

Here are some practical guidance and recommended approaches on using the CICS asynchronous API. However, your environments and applications might vary and benefit from different approaches. For details, see the IBM® Redbooks® publication IBM CICS Asynchronous API: Concurrent Processing Made Simple.

Child tasks should perform GETs of data and leave UPDATEs to the parent task.
Parent and child tasks are separate units of work (UOW). If, for example, a parent abends, it can back-out its own work but will be unconnected from the execution of the child tasks. If the child tasks are limited to GET actions, they can be safely discarded without compromising the state of the data. It is possible for child tasks to perform UPDATEs on data. However, you might be required to code compensation logic to revert changes, if the need arises.
Allow the same parent program to run and fetch child tasks.
For manageability, the parent program that begins a child task should remain the program that fetches the results from the child task. This process is particularly useful if you are using the FETCH ANY command, because it can become difficult to match the RUN TRANSID to FETCH ANY commands if they reside in different programs. Also note that fetched channels are scoped to a link level. So passing results can be problematic if it is not the parent that fetches the child's results.
Tip: If you want to retrieve response data from a child task, specify CHANNEL in EXEC CICS RUN TRANSID even if you have no input data to the child task.
Long-running parents should use the FREE CHILD command.
In a long-running parent application, there can be a build-up to control blocks as child tasks complete. In addition, there can be a build-up of sizeable channel data. Without task termination, the CICS system cannot safely discard this data. It is advisable that a long-running parent task deletes any fetched channels and issues FREE CHILD commands against child tasks that are no longer required.
Keep track of fetched channels.
Data is passed between parent and child tasks using CICS channel and containers. To return data from a child, the child task updates containers on its current channel. During the termination of child tasks, the channel is managed or owned by the CICS AS domain. The parent task can retrieve the child’s channel by specifying the CHANNEL parameter on the FETCH CHILD or FETCH ANY commands. This approach is more active than a simple inquiry. The channel will bind to the issuing parent.
Review MAXTASK and set transaction classes.
The simplicity of the asynchronous API might generate more transactions in a CICS system. It's recommended to review the MAXTASK parameter setting. It is advised to have controls in place to limit the amount of work that a region accepts that cause tasks to be run asynchronously.
Parameterize timeouts.
In many cases, the results of a child are needed for the parent to continue their business logic. If you require a timeout, or if there is a possibility that you might need to in future, you can code the parent to specify a TIMEOUT parameter on the FETCH command. The value of the timeout should be parameterized, such as being read from a file or database table, earlier in the application. By inserting the TIMEOUT parameter and parameterizing the TIMEOUT value, you prevent the need for a future code update or recompilation.
You can use TIMEOUT and NOSUSPEND on your FETCH CHILD and FETCH ANY commands to improve application versatility and meet business needs in a variety of situations:
  • For any child tasks from which you will definitely need a response, use FETCH without TIMEOUT or NOSUSPEND.
  • For child tasks from which you need the response in a timely fashion, specify a TIMEOUT value on your FETCH command.
  • For child tasks where no response is acceptable, specify NOSUSPEND on your FETCH command.

Examples

Example: A credit card application

In this example, a credit card application is used to demonstrate how the commands can be used.

Start the credit check child tasks
  1. Put the customer details onto a new channel:.
    EXEC CICS PUT CONTAINER('CUSTDETAILS') CHANNEL(customerDetails)
  2. Call the first credit check service with a channel:
    EXEC CICS RUN TRANSID('CRD1') CHILD(creditCheck1_tkn) CHANNEL(customerDetails)
  3. Call the second credit check service with the same channel:
    EXEC CICS RUN TRANSID('CRD2') CHILD(creditCheck2_tkn) CHANNEL(customerDetails)

A parent program can continue with other processing after issuing an EXEC CICS RUN TRANSID command, and can issue an EXEC CICS FETCH command at any point afterward to retrieve the results of a child task.

Get a response from a specific child task
  1. Fetch the response from the first child:
    
    EXEC CICS FETCH CHILD(creditCheck1_tkn) CHANNEL(credReply1_chan) 
              COMPSTATUS(credReply1_status)

    In this case, parent processing is blocked until the child task returns a result. Use of the optional parameters NOSUSPEND and TIMEOUT can prevent or limit blocking as preferred.

  2. Check the response code of the EXEC CICS FETCH CHILD command to ensure the command executed normally.
  3. If the EXEC CICS FETCH CHILD command executed normally, then check the COMPSTATUS of the child to ensure it completed successfully.
    • If COMPSTATUS indicates that the child task completed successfully, then get the response from the reply channel.
      EXEC CICS GET CONTAINER('RESULT') CHANNEL(credReply1_chan)
    • If COMPSTATUS indicates that the child task abended, then the logic of the parent application should decide what to do. CICS will clean up all resources when the parent transaction completes.
  4. Repeat steps 1 through 3 for the second child task.
Get a response from any completed child task

It's also possible to fetch a response from any completed child task using the EXEC CICS FETCH ANY command, which will return the result of whichever child task completed first:


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

Check the completion of the FETCH ANY command and the child's COMPSTATUS as normal.

Free a child

As part of your parent task, you can choose to free child tasks, which will tidy up the associated resources and keep system storage use to a minimum, which is especially useful for long-running parent tasks. If, for example, you started three child tasks, but only need the results of one, then you can clean up the remaining two child tasks using FREE CHILD.


EXEC CICS FREE CHILD(creditCheck1_tkn)
EXEC CICS FREE CHILD(creditCheck2_tkn)
Table 1. Reference: Optional parameters
Command Optional parameter Usage
EXEC CICS RUN TRANSID CHANNEL Use it to:
  • Pass data to a child.
  • Receive data from a child.
  • Both pass and receive data to and from a child.
RESP Use it to see if a command executed successfully
EXEC CICS FETCH commands CHANNEL Use it to receive data from a child task, as long as a channel was supplied on the initial RUN TRANSID command.
NOSUSPEND Use it to stop a FETCH command from blocking: the command will return immediately regardless of whether a child task has completed.

If the child task has finished when the command is issued, the command will return immediately with a NORMAL response. If the child hasn’t finished, the NOTFINISHED condition will occur with RESP2 value of 52.

TIMEOUT Use it to make a FETCH command wait for a specified amount of time before returning.

You can specify the maximum time in milliseconds that the parent task will wait for a child task to complete. When TIMEOUT is specified with a non-zero value, the parent task will not be subject to DTIMOUT.

If the child task finishes before TIMEOUT is reached, the command will return immediately. If the child task hasn’t finished before TIMEOUT is reached, a NOTFINISHED condition will occur with a RESP2 value of 53.

ABCODE If COMPSTATUS indicates that a child has abended, then ABCODE will contain the abend code of the child.

Example: Passing the child token to a linked program to fetch response from the child task

The following steps are an example of how input and output are passed between parent and child tasks using channels.

  1. The parent task, PROGP1, passes input to a child task in a channel, and then links it to a local program 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')

    A copy of the ASYNC-CHANNEL created by the parent is passed to the child, and the copy becomes the current channel for the child's initial program. The name of the channel is retained by the copying process, so if the child program PROGC1 issued EXEC CICS ASSIGN CHANNEL then ASYNC-CHANNEL would be returned.

  2. The child task, with transaction ID CHLD and program PROGC1, gets the input from its current channel:
    EXEC CICS GET CONTAINER('REQ')

    The child will then continue with its logic, generate a response for the parent task, and then put it into a container within its current channel:

    
    EXEC CICS PUT CONTAINER('RESP') FROM(RESPONSE)
    EXEC CICS RETURN
  3. The parent task, PROGP2, fetches the child response and continues with some business logic before returning to 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)

    When the parent task fetches the response channel from the child, CICS generates a unique channel name and binds the channel to the current program link level. In this example, the fetched channel will be owned by PROGP2. When PROGP2 returns to PROGP1, the fetched channel will be deleted by CICS. A child's response channel can only be fetched once by the parent task.

Example: CICS Asynchronous API Fetch variation

Before you begin: The source code for this example is available in full on GitHub where you will also find setup and running instructions.

This COBOL example has a parent program ASYNCPG1 to demonstrate the use of EXEC CICS FETCH commands with and without option TIMEOUT or NOSUSPEND. The application also have four child programs: ASYNCCH1, ASYNCCH2, ASYNCCH3, ASYNCCH4.

ASYNCPG1 starts four asynchronous child tasks. It then does 3 different flavors of fetch to get the response, according to the business requirement, as following:
  • The parent program needs the response from the first child, so use FETCH CHILD with no SUSPEND or TIMEOUT option.
    
    EXEC CICS FETCH CHILD(CHLDTOKN1) CHANNEL(CHLDCHNL1)
               COMPSTATUS(CVDA)
               RESP(W-RESP) RESP2(W-RESP2)
               END-EXEC.
  • The parent program can wait for up to 1000 milliseconds when fetching the response from the second child, so use FETCH CHILD TIMEOUT.
    
    EXEC CICS FETCH CHILD(CHLDTOKN2) CHANNEL(CHLDCHNL2)
               TIMEOUT(TIMEOUT1)
               COMPSTATUS(CVDA)
               RESP(W-RESP) RESP2(W-RESP2)
               END-EXEC.
    where TIMEOUT1 is defined as shown below and can be changed dynamically in the program or by reading from a file or database to suit your environment:
    01 TIMEOUT1     PIC S9(8) USAGE BINARY VALUE 1000.
  • For the third and fourth children, the parent program can have any result, but can't afford to wait, so use FETCH CHILD NOSUSPEND.
    
    EXEC CICS FETCH ANY(ANYTOKN) CHANNEL(ANYCHNL)
               NOSUSPEND COMPSTATUS(CVDA)
               RESP(W-RESP) RESP2(W-RESP2)
               END-EXEC.