Compaq ACMS for OpenVMS
Writing Applications


Previous Contents Index

8.5.2 Recovering from a Task-Call-Task Exception

If an exception occurs in a called task, you might want to continue executing the parent task rather than letting ACMS cancel it. You can specify an exception handler action in the processing step that called the task or on an outer block step in the parent task. Note that the CONTINUE ON BAD STATUS phrase is a declining feature that has been superseded by the exception handler mechanism. Do not use it in new task definitions. Example 8-4 shows part of a parent task that includes an exception handler action to recover from possible exceptions raised in the called task.

Example 8-4 Recovering from an Exception Raised in a Called Task

COMPLETE_PROC: 
 
! CALL THE VR_COMPLETE_CHECKOUT_TASK TO COMPLETE THE CHECKOUT 
! TRANSACTION. 
! 
! 
    PROCESSING 
        CALL TASK       VR_COMPLETE_CHECKOUT_TASK 
        USING           VR_SENDCTRL_WKSP, 
                        VR_CONTROL_WKSP, 
                        VR_RESERVATIONS_WKSP, 
                        VR_TRANS_WKSP, 
                        VR_VEHICLES_WKSP; 
! 
! THE DISTRIBUTED TRANSACTION IS STARTED IN THE VR_COMPLETE_CHECKOUT_TASK 
! BUT IS NOT EXPLICITLY COMMITTED SINCE IT IS A COMPOSABLE TASK. THE 
! COMMIT WILL BE PERFORMED BY ACMS (DEFAULT ACTION). 
! 
 
    ACTION IS 
        MOVE "     " TO VR_CONTROL_WKSP.CTRL_KEY, 
             "ACTWT" TO VR_SENDCTRL_WKSP.SENDCTRL_KEY; 
! 
! RETRY IF A TIME OUT ERROR OCCURRED BEFORE CANCELING TASK. 
! 
    EXCEPTION HANDLER 
        IF ( (ACMS$L_STATUS = ACMS$_TRANSTIMEDOUT AND 
                VR_CONTROL_WKSP.RETRY_COUNT = 0) ) 
        THEN 
             MOVE 1       TO VR_CONTROL_WKSP.RETRY_COUNT; 
             REPEAT STEP; 
        ELSE 
             GET MESSAGE INTO VR_CONTROL_WKSP.MESSAGEPANEL; 
             MOVE "     " TO VR_CONTROL_WKSP.CTRL_KEY, 
                  "ACTWT" TO VR_SENDCTRL_WKSP.SENDCTRL_KEY; 
             GOTO STEP DISP_STAT; 
        END IF; 
 
! 
! DISPLAY STATUS TO THE USER. 
! 
DISP_STAT: 
 
    EXCHANGE 
        SEND RECORD             VR_CONTROL_WKSP 
        SENDING                 VR_CONTROL_WKSP 
        WITH SEND CONTROL       VR_SENDCTRL_WKSP; 
             
 

In Example 8-4, the COMPLETE_PROC processing step calls the VR_COMPLETE_CHECKOUT_TASK to compute the customer's bill and perform final checkout work. The VR_COMPLETE_CHECKOUT_TASK starts a distributed transaction. Because VR_COMPLETE_CHECKOUT_TASK is a composable task, it cannot explicitly commit or roll back the distributed transaction. Because a distributed transaction must end in the action part of the step where it starts, ACMS provides the default transaction action.

The exception handler part of the parent task uses an IF THEN ELSE conditional clause to test the contents of the ACMS$L_STATUS field in the ACMS$PROCESSING_STATUS workspace. If the called task raises the ACMS$_TRANSTIMEDOUT exception code, ACMS retries the called task once.

If a called task completes without raising an exception, ACMS returns the contents of any modify-access and write-access task argument workspaces to the parent task. ACMS then resumes executing the task from the action part of the processing step that called the task.

If a called task completes with an exception, ACMS does not return the contents of task argument workspaces to the parent task. If a task, called by a parent task that does not start a distributed transaction, completes with any type of exception, ACMS raises a step exception in the parent task. If a called task that participates in a distributed transaction started by the parent task completes with a step exception, ACMS raises a step exception in the parent task. If a called task that participates in a distributed transaction completes with a transaction or nonrecoverable exception, ACMS raises a transaction exception in the parent task.

8.5.3 Recovering from a Transaction Exception

If your task includes a distributed transaction, there are several exceptions you may want to test for and recover from by including an exception handler in the task definition. A communication link between nodes participating in the distributed transaction could be broken, or a resource manager that is part of the distributed transaction might detect an error and be unable to prepare its part of the distributed transaction. Example 8-5 shows how to test for and recover from a transaction exception.

Example 8-5 Recovering from a Transaction Exception

BLOCK WITH TRANSACTION 
 
!+ 
! ONLY UPDATE CUSTOMER RECORD IF SHADOW RECORD INDICATES 
! CHANGE HAS BEEN MADE ON PREVIOUS EXCHANGE. 
 
    IF ( (VR_CUSTOMERS_SHADOW_WKSP.REC_STATUS = "1") OR 
         (VR_TRANS_SHADOW_WKSP.REC_STATUS = "1")     OR 
         (VR_SENDCTRL_WKSP.SENDCTRL_KEY = "TRAGN") ) THEN 
 
        PROCESSING 
 
            CALL PROCEDURE VR_STORE_CU_PROC 
            IN      VR_CU_UPDATE_SERVER 
            USING   VR_CONTROL_WKSP, 
                    VR_CUSTOMERS_WKSP, 
                    VR_TRANS_WKSP; 
 
        ACTION IS 
            IF (ACMS$T_STATUS_TYPE = "B") THEN 
                GET MESSAGE INTO VR_CONTROL_WKSP.MESSAGEPANEL; 
                MOVE "TRAGN" TO VR_SENDCTRL_WKSP.SENDCTRL_KEY; 
                EXIT BLOCK; 
            ELSE 
                MOVE "     " TO VR_CONTROL_WKSP.CTRL_KEY, 
                     "     " TO VR_SENDCTRL_WKSP.SENDCTRL_KEY; 
            END IF; 
    END IF; 
 
STORE_RESV: 
!+ 
! CREATE RESERVATION NUMBER AND WRITE RESERVATION RECORD TO DB. 
!- 
    PROCESSING 
        CALL PROCEDURE  VR_WRITE_RS_PROC 
        IN      VR_UPDATE_SERVER 
        USING   VR_CONTROL_WKSP, 
                VR_RESERVATIONS_WKSP, 
                VR_SITES_WKSP, 
                VR_RENTAL_CLASSES_WKSP, 
                VR_CUSTOMERS_WKSP; 
 
    ACTION 
        MOVE "RESERVE " TO VR_HIST_WKSP.TRANS_TYPE; 
 
!+ 
! WRITE A RECORD TO THE HISTORY FILE TO LOG THE COMPLETED TRANSACTION 
! - HISTORY RECORDS ARE RDB RECORDS (COULD BE ANY TYPE OF FILE SYSTEM 
! OR DATABASE). THIS IS PART OF THE DISTRIBUTED TRANSACTION. 
!- 
 
    PROCESSING 
 
        CALL PROCEDURE  VR_WRITE_HIST_RECORD_PROC 
        IN      VR_LOG_SERVER 
        USING   VR_HIST_WKSP, 
                VR_RESERVATIONS_WKSP; 
 
! 
! END OF DISTRIBUTED TRANSACTION 
! 
END BLOCK; 
 
    ACTION  IS 
        IF (ACMS$T_STATUS_TYPE = "G") 
 
        THEN 
                COMMIT TRANSACTION; 
                MOVE "     " TO VR_SENDCTRL_WKSP.SENDCTRL_KEY, 
                     "Y"     TO VR_CONTROL_WKSP.INCREMENT_RETRY_COUNT, 
                      0      TO VR_CONTROL_WKSP.RETRY_COUNT; 
        ELSE 
                ROLLBACK TRANSACTION; 
                GOTO STEP DISPLAY_CUST_INFO; 
        END IF; 
! 
! EXCEPTION HANDLER FOR ABOVE BLOCK 
! 
! RETRY THE DISTRIBUTED TRANSACTION 5 TIMES (ONLY IF A 
! ACMS$_TRANSTIMEDOUT ERROR OCCURRED) BEFORE CANCELING TASK. 
! THE RETRY_COUNT IS INCREMENTED IN EITHER VR_STORE_CU_PROC 
! OR VR_WRITE_RS_PROC. 
! 
    EXCEPTION HANDLER 
         IF (ACMS$L_STATUS = ACMS$_TRANSTIMEDOUT AND 
             VR_CONTROL_WKSP.RETRY_COUNT < 5) 
         THEN 
            REPEAT STEP; 
         ELSE 
            GET MESSAGE INTO VR_CONTROL_WKSP.MESSAGEPANEL; 
            MOVE "ACTWT" TO  VR_SENDCTRL_WKSP.SENDCTRL_KEY, 
                 "     " TO VR_CONTROL_WKSP.CTRL_KEY; 
            GOTO STEP DISP_STAT; 
         END IF; 
 

In this example, a nested block starts a distributed transaction and includes three processing steps. The first processing step checks to see if the user has changed any customer information. If one of the shadow workspaces indicates that information has changed, the processing step calls the VR_STORE_CU_PROC procedure to update the database.

The STORE_RESV step adds a reservation record to the reservation database. The third processing step updates a transaction log in another database.

If the three processing steps complete successfully, the action part of the nested block step commits the distributed transaction. If an error occurs that causes the distributed transaction to fail before completing, ACMS raises a transaction exception. The exception handler part of the nested block checks for the ACMS$_TRANSTIMEDOUT transaction exception code to see if the distributed transaction did not complete within the time limit specified in the application definition with the TRANSACTION TIMEOUT phrase.

If the ACMS$L_STATUS field contains the ACMS$_TRANSTIMEDOUT exception code, ACMS repeats the block step up to five times. If ACMS$L_STATUS contains any other exception code, or if the distributed transaction has already timed out five times, ACMS passes control to the DISP_STAT exchange step, which displays an error message, and ends the task.

8.6 How ACMS Performs Exception Handling

To be able to design tasks that make efficient use of exception handling, you need to know how ACMS executes tasks that use exception handling. ACMS takes different actions depending upon the type of exception and where in the task definition the exception was raised; however, for step exceptions and transaction exceptions, ACMS performs the following steps:

  1. Interrupts task execution. If the exception is raised while ACMS is executing an exchange step, ACMS cancels the exchange I/O. If the exception is raised while ACMS is executing a processing step, ACMS cancels a call to a server procedure or DCL command.
  2. Searches for an exception handler. When ACMS finds an exception handler, ACMS stores the exception code in the ACMS$PROCESSING_STATUS system workspace, and evaluates the conditional clause, if present. If no exception handler has been specified, ACMS cancels the task.
  3. Executes the exception handler action clauses. Regardless of the order in which the action clauses appear in the definition, ACMS processes them in the following order:
    1. Workspace manipulation
    2. Server context action
    3. Task sequencing

The following sections describe how ACMS executes each type of exception, and how ACMS cancels a task.

8.6.1 Executing a Step Exception Outside of a Distributed Transaction

If ACMS detects a step exception outside the bounds of a distributed transaction, ACMS first looks for an exception handler on the same step that raised the exception. If the current step does not include an exception handler, ACMS checks block steps out to the root block step for an exception handler. If ACMS does not find an exception handler, it cancels the task. If ACMS finds an exception handler, it stores the exception code in ACMS$PROCESSING_STATUS and performs the exception handler action clauses. If the exception handler does not specify how to handle the particular exception raised, ACMS searches out to the root block for another exception handler. If ACMS cannot find an exception handler that specifies how to handle the particular exception raised, ACMS raises a nonrecoverable exception and cancels the task. For example, if the exception handler specifies a recovery action only for the FORMS$_TIMEOUT exception code, and a different exception is raised, ACMS cancels the task.

8.6.2 Executing a Step Exception Within a Distributed Transaction

If ACMS detects a step exception within a distributed transaction, ACMS searches for an exception handler on the current step. If the current step does not include an exception handler, ACMS searches any outer block steps within the distributed transaction. If ACMS finds an exception handler, ACMS performs the exception handler action clauses.

If ACMS does not find an exception handler, or if the exception is raised in a processing step that starts a distributed transaction, ACMS checks to see whether the distributed transaction was started by the current task, a parent task, or an agent. If the current task started the distributed transaction, ACMS aborts the distributed transaction and raises a transaction exception with the same exception code. If the current task is a called task that participates in a distributed transaction started by the parent task or an agent, ACMS cancels the current task and raises a transaction exception in the parent task, or returns the exception code to the agent.

8.6.3 Executing a Transaction Exception

As with step exceptions, when ACMS detects a transaction exception, it interrupts the task execution. If the task was not executing a COMMIT TRANSACTION clause when the transaction exception was raised, ACMS calls the server cancel procedure, if defined, for each server in which the task maintains context. If the task was executing COMMIT TRANSACTION, ACMS does not call any server cancel procedures. Before searching for an exception handler, ACMS releases context held in server processes.

ACMS then searches for an exception handler, starting on the step that started the distributed transaction and searching out to the root block.

8.6.4 Executing Nonrecoverable Exceptions

When ACMS detects a nonrecoverable exception, it interrupts the task execution and begins to cancel the task. ACMS performs the following steps to cancel a task:

  1. Handles an active distributed transaction. If a distributed transaction is active, and the task is not a called task that participates in a distributed transaction started by the parent task or agent, ACMS aborts the distributed transaction. If the task is a called task that joins a distributed transaction, the parent task or agent that started the distributed transaction must abort it.
  2. Calls the server cancel procedure for each server in which the task maintains context.
  3. Writes a task cancellation record to the ACMS audit trail log.
  4. Executes the task's CANCEL ACTION processing work, if defined.
  5. If task is a called task, returns an exception to the parent task or agent.

8.7 How Exceptions Affect Server Cancel Procedures

When you define the characteristics of a server in the task group definition, you can specify a server cancel procedure. Server cancel procedures perform cleanup work when a task cancels. For example, a server cancel procedure might close a channel that was opened for terminal I/O, release resources used by a server procedure such as an OpenVMS lock, or roll back a database recovery unit. However, calling server cancel procedures after an exception has been raised can adversely affect the performance of your application, because ACMS must make an additional call to each server process.

If an exception causes the server process to be run down, calling a server cancel procedure increases the time it takes to shut down and restart the server process. If the server process does not have to be run down, calling a server cancel procedure causes a delay in allocating the server process to another task instance. Therefore, wherever possible, design tasks and step procedures that do not call server cancel procedures when an exception has been raised. The following sections describe how ACMS uses the exception type to determine when to call server cancel procedures.

8.7.1 Step Exceptions and Server Cancel Procedures

If a step exception is raised, and the task definition does not include an exception handler to recover from the exception, ACMS raises a transaction exception or a nonrecoverable exception. If a distributed transaction was active when the step exception was raised, ACMS raises a transaction exception; otherwise, ACMS raises a nonrecoverable exception. ACMS then calls any server cancel procedures and cancels the task.

ACMS does not call server cancel procedures when a step exception is raised and the task definition includes an exception handler to recover from the exception.

8.7.2 Nonrecoverable Exceptions Raised by Action Clauses

If a nonrecoverable exception is raised while a task maintains context in one or more server processes, ACMS calls server cancel procedures. If the action part of the step in which the nonrecoverable exception is raised releases server context, ACMS does not call server cancel procedures. The action part of the processing step in the following example explicitly releases server context.


PROCESSING 
   CALL UPDATE_ORDER_IN ORDER_SERVER USING ORDER_RECORD; 
ACTION IS 
   IF (ACMS$L_STATUS <> 1) 
   THEN 
      RELEASE SERVER CONTEXT; 
      CANCEL TASK RETURNING ACMS$L_STATUS; 
   END IF; 

Because ACMS executes server context actions before sequencing actions, ACMS releases server context before canceling the task. Therefore, ACMS does not call server cancel procedures.

The processing step in the previous example did not participate in a distributed transaction. Within a distributed transaction, ACMS requires that server context be retained between steps. Therefore, if a processing step within a distributed transaction cancels the task, ACMS calls server cancel procedures. Example 8-6 shows how to cancel a task within a distributed transaction without calling server cancel procedures.

Example 8-6 Canceling a Task without Calling Server Cancel Procedures

BLOCK WORK WITH DISTRIBUTED TRANSACTION 
   PROCESSING 
      CALL UPDATE_ORDER IN ORDER_SERVER 
           USING ORDER_RECORD; 
   ACTION IS 
      IF (ACMS$L_STATUS <> 1) 
      THEN 
         EXIT BLOCK; 
      END IF; 
   PROCESSING 
      CALL WRITE_LOG_RECORD IN LOG_SERVER 
           USING ORDER_RECORD; 
END BLOCK; 
ACTION IS 
   IF (ACMS$L_STATUS = 1) 
   THEN 
      COMMIT TRANSACTION; 
   ELSE 
      ROLLBACK TRANSACTION; 
      CANCEL TASK RETURNING ACMS$L_STATUS; 
   END IF; 

Example 8-6 starts a distributed transaction on the block step. If the UPDATE_ORDER procedure returns a status value other than 1, ACMS passes control to the action part of the block step, rolls back the distributed transaction, and cancels the task. When ACMS processes the ROLLBACK TRANSACTION clause, the distributed transaction ends and ACMS releases server context. As a result, ACMS does not call server cancel procedures when it cancels the task.

8.7.3 Other Nonrecoverable Exceptions and Transaction Exceptions

When ACMS executes a COMMIT TRANSACTION clause, if a transaction exception is raised because the distributed transaction fails to prepare, ACMS does not call server cancel procedures.

In all other cases, if a transaction exception or a nonrecoverable exception is raised while the task maintains context in one or more server processes, ACMS calls server cancel procedures.


Chapter 9
Queuing ACMS Tasks

ACMS typically does interactive processing of the tasks in your application, but certain tasks have requirements that you can meet through the use of task queues. These requirements include:

For these and other such requirements, you can use the ACMS queuing facility to capture and initiate the tasks in your ACMS application.

9.1 Understanding the ACMS Queuing Facility

In an ACMS application, exchange steps of a task gather data while processing steps of that task process the data.

When you use ACMS queuing, you may include in a processing step a call to an ACMS programming service to enqueue a deferred task on a task queue for later processing. This queued task includes task arguments, together with a task name, and an application name, to comprise a queued task element that is stored on the task queue. At a later time, ACMS executes a queued task (a task submitted by the ACMS queuing facility). ACMS processes the queued task and then deletes the queued task element from the task queue. In other words, a queued task element is stored in a task queue for later processing.

Queued tasks must have certain characteristics (discussed in Section 9.6.1) in order for them to be successfully executed by the ACMS queuing facility. For example, queued tasks cannot perform exchange steps to collect input, because all the input needed by the queued task must be passed to the task as task arguments. Aside from these characteristics, there is no difference between a queued task and any other ACMS task.

Note

ACMS task queues are distinct from OpenVMS batch queues. Many of the concepts are similar, but ACMS and OpenVMS queues are completely independent entities that are managed and used by independent interfaces.

You use the following components of the ACMS queuing facility to implement, manage, and execute your queuing applications:

Figure 9-1 shows how to use the ACMS$QUEUE_TASK service to queue tasks, and how to use the QTI to dequeue and initiate tasks in the queue.

Figure 9-1 Queuing, Dequeuing, and Processing Tasks


In Figure 9-1:


Previous Next Contents Index