# Compaq ACMS for OpenVMS
Writing Applications

Previous | Contents | Index

1. A high-level language, user-written program calls the ACMS$QUEUE_TASK service to store a queued task element in a task queue. Any data needed by the queued task is passed to the ACMS$QUEUE_TASK service and is stored with the queued task element.
2. The QTI process dequeues the queued task element and initiates the queued task in the specified application. The queued task element remains on the task queue as the queued task executes, but it is unavailable for dequeuing. When the queued task completes, the QTI process deletes the queued task element from the queue.
3. If the queued task fails, the QTI automatically retries the task until it determines the task cannot succeed. Then the QTI places the task on the error queue associated with the task queue. If no error queue exists, the QTI removes the task from the queue.

Queues can be shared within a cluster. Therefore, you can have user-written procedures, ACMS applications, and QTI processes that are spread across several nodes in the same cluster, and can queue and dequeue tasks to the same task queue.

The application can be on the same node or on the same cluster as the QTI, or anywhere on the network (using DECnet). The QTI locates the application using an application specification that uses the same semantics (logical names, search lists, and failover) that exist for invoking interactive tasks.

# 9.2 Using ACMS Queuing with Distributed Transactions

In writing applications that use queue services, you must be concerned with ensuring the integrity of task queues and databases in the event of abnormal system failures (such as a machine crash or a disk failure). For example, if the QTI calls a task and the task completes, but the application node crashes before the QTI is notified that the task completed, the QTI retries the task. Prior to ACMS Version 3.2, the QTI did not know whether the task successfully updated a database. Therefore, when the QTI retries the task, the database might be updated again.

If it is critical that each queued task element update the database exactly once, include queue operations in an atomic transaction. In an atomic transaction, each operation must complete successfully for the transaction to be successful. If one operation fails, the effects of the other operations are undone. An atomic transaction that includes operations involving multiple resources, such as a task queue and a database, is a distributed transaction.

The OpenVMS operating system provides a set of transaction services, DECdtm services, that ACMS uses to control distributed transactions. ACMS lets you use distributed transactions to coordinate the removal of queued task elements from a task queue with updates to a database or file. Likewise, you can coordinate the insertion of queued task elements to a task queue with database updates in a distributed transaction. If all operations in the distributed transaction complete successfully, ACMS calls the transaction services to commit, or make permanent, the effects of the operations. If any of the operations in the distributed transaction fail, ACMS calls the transaction services to roll back, or undo, the effects of the operations. In this way, ACMS ensures that updates to databases or files by the queued task are performed exactly once.

Note If your application is distributed across OpenVMS Cluster systems, each system must be running ACMS Version 3.2 or higher; otherwise, tasks participating in distributed transactions might have unpredictable results.

To include a queued task in a distributed transaction, you must mark the task queue file for recovery-unit journaling by using the SET FILE/RU_JOURNAL DCL command. Any task queue file not marked for recovery-unit journaling cannot participate in a distributed transaction. In addition, for a queued task to be able to join an existing distributed transaction, the queued task must conform to the following rules:

- The root block or root processing step must include the TRANSACTION phrase.
- The root block or root processing step cannot include a sequencing action clause other than EXIT TASK, CANCEL TASK, or RAISE EXCEPTION.
- The root block or root processing step cannot include the COMMIT TRANSACTION or ROLLBACK TRANSACTION action clause.
- The root block or root processing step cannot include an exception handler.
- The root block or root processing step cannot include the CANCEL ACTION phrase.

A task that conforms to these rules is said to be a composable task.

When ACMS calls DECdtm to start a distributed transaction, DECdtm returns a unique transaction identifier (TID). The ACMS$QUEUE_TASK and ACMS$DEQUEUE_TASK services use the default TID.

At run time, the QTI process starts a distributed transaction for task queues marked for recovery-unit journaling, dequeues the queued task element from the task queue, and initiates the queued task in the specified application. If the task completes successfully, the QTI process deletes the queued task element from the task queue and commits the transaction.

If the queued task fails, the QTI process aborts the distributed transaction which rolls back any updates the queued task made to a database or file, and restores the task queue to the state it was in prior to the distributed transaction. The QTI process then starts another transaction and, depending on the reason for the task failure, performs one of the following actions:

- Retries the queued task element
- Moves the queued task element to an error queue
- Deletes the queued task element from the task queue if there is an error queue

See Section 9.6.4 for details on how the QTI handles errors.

# 9.3 Steps in Using ACMS Queuing

The following is a list of the management and programming steps you must take to use queuing:

1. Create a task queue using the ACMSQUEMGR Utility. You must create a queue before the ACMS Queued Task services or the QTI run-time component can access that queue.
2. Create an error queue, if needed, using the ACMSQUEMGR Utility.
3. Enable RMS journaling using the DCL SET FILE/RU_JOURNAL command for task queue files, if the queued tasks are to participate in a distributed transaction.
4. Set ACMSGEN parameters for the QTI process.
5. Place queued task elements onto the task queue by using the ACMS$QUEUE_TASK service. The service can be called from a step procedure or from a standalone program. If the service is called from a step procedure, and you want to include the queue operations in a distributed transaction, include the TRANSACTION phrase in the task definition. If the service is part of a standalone program, use the $START_TRANS system service to include the queue operations in a distributed transaction.
6. Start the QTI process by using the ACMS/START QTI operator command.
7. Start one or more task queues and specify the error queue to be associated with the task queues by using the ACMS/START QUEUE operator command.
8. Process the error task queues, if any, in whatever manner is appropriate for your application. For example, if elements on the error queue could be corrected by a terminal user, then define a task to:
   - Dequeue an element from the error task queue using the ACMS$DEQUEUE_TASK service called from a step procedure
   - Display the data fields to the terminal user and accept corrections using an exchange step
   - Queue the corrected element back to the task queue using the ACMS$QUEUE_TASK service from a step procedure
9. Periodically perform routine maintenance on the task queue files.

The remainder of this chapter contains information about using many of these steps. Compaq ACMS for OpenVMS Managing Applications describes how to use the ACMSQUEMGR Utility and ACMS operator commands affecting queues. ACMS$QUEUE_TASK and ACMS$DEQUEUE_TASK contain reference information on the ACMS$QUEUE_TASK and ACMS$DEQUEUE_TASK services.

Considerations for providing queue security are described in Section 9.4.

# 9.4 Defining Queue Security

When you use the CREATE QUEUE command to create a queue, the ACMSQUEMGR Utility sets the owner of the queue file to [1,4] and sets the protection of the file to O:RWED,S:RWED,G,W. Therefore, to access the queue file, a user must have a system UIC or must have the SYSPRV privilege.

Access to a task is distinct from access to a task queue. Task security is defined by an access control list (ACL) in the application definition. (For information on the user name under which queued tasks can run and, therefore, the user name used to determine access to a task, see Section 9.5.1.)

The queue services used from within application programs to access queues have the following access to the queue file:

- The ACMS$QUEUE_TASK service that you use to queue tasks enables the SYSPRV privilege (only for the purpose of accessing the queue file) so it can always access the queue file. Therefore, any user can store a queued task element on any queue. The ACMS$QUEUE_TASK service always enables SYSPRV in order to gain write access to the queue file. SYSPRV is disabled after the ACMS$QUEUE_TASK call completes.
- The ACMS$DEQUEUE_TASK service that you use to dequeue tasks does not enable the SYSPRV privilege and cannot access the queue file automatically. Therefore, any process that uses the ACMS$DEQUEUE_TASK service must have the SYSPRV privilege or a system UIC; only privileged users can dequeue tasks.

The QTI process has the SYSPRV privilege and is, therefore, able to access the queue file to dequeue tasks.

You can use OpenVMS security interfaces to override the default queue security. For example, you can use the DCL SET FILE command to change the owner of the queue file or the protection on the queue file. You can also define an access control list for the queue file.

# 9.5 Using the ACMS Queue Services to Queue and Dequeue Tasks

There are two ACMS queue services:

- ACMS$QUEUE_TASK
  Stores the queued task element in a task queue. You call the ACMS$QUEUE_TASK service from a standalone program or a step procedure written in any OpenVMS-supported language.
- ACMS$DEQUEUE_TASK
  Dequeues, or optionally reads, a queued task element from a queue and returns information about the queued task element.

Any process, including a procedure server in an ACMS application, can call these services. You cannot call these services from a program run in a DCL server. A step procedure or standalone program can call these services from user mode at AST or non-AST level. These services are not AST reentrant. A service that is being called at non-AST level cannot be interrupted by an AST-level call to the service.

Compaq ACMS for OpenVMS Writing Server Procedures shows the calling sequence of the ACMS$QUEUE_TASK service and the ACMS$DEQUEUE_TASK service.

Section 9.7 and Section 9.10 contain examples of procedures that use these services.

## 9.5.1 Queuing Tasks Using the ACMS$QUEUE_TASK Service

Once you have created a task queue using the ACMS Queue Manager (ACMSQUEMGR) Utility, you can queue tasks using the ACMS$QUEUE_TASK service. You place tasks onto the queue from either a step procedure or a standalone program that calls the ACMS$QUEUE_TASK service. Before calling ACMS$QUEUE_TASK, the task or standalone program gathers the information necessary to run the task. Before queuing the task, you might want to perform some of the processing, as well. If you want the queued task to be part of a distributed transaction, you must declare the start of the distributed transaction, either in the task definition by using the TRANSACTION phrase or in the standalone program by using the $START_TRANS service.

The ACMS$QUEUE_TASK service passes several parameters including the queue name (which cannot contain trailing spaces), the task name, the name of the application in which the task is to run, as well as the data to be passed in the workspaces. You can optionally include parameters that assign a priority to the queued task element, place the queued task element in a hold state (make it unavailable for dequeuing), supply a user name under which you want the task to run, and request that the ACMS$QUEUE_TASK service return a unique element ID of the queued task element. The ACMS$QUEUE_TASK service queues the task element and its parameters onto the specified queue.

Associated with each queued task element is an enqueuer user name. Provided that the QTI runs under a user name that has the ACMS agent privilege in the User Definition Utility (UDU) user authorization file, the QTI submits tasks under the enqueuer user name. Access to the task and access to the resources used by the task are granted or denied based on the access rights of this user name. By default, the enqueuer user name is the user name of the process that called the ACMS$QUEUE_TASK service. A user name other than the process user name can be passed to ACMS$QUEUE_TASK as the enqueuer user name if the process has the OpenVMS CMKRNL privilege.

## 9.5.2 Dequeuing Task Elements Using the ACMS$DEQUEUE_TASK Service

As with the ACMS$QUEUE_TASK service, any process, including a procedure server process, can call the ACMS$DEQUEUE_TASK service. To have the dequeue operation coordinated with other resource manager operations, such as database updates, you must have declared the start of a distributed transaction, either in the task definition by using the TRANSACTION phrase or in the procedure by using the $START_TRANS system service. The most common use of the ACMS$DEQUEUE_TASK service is for taking queued task elements off an error queue, although it is possible to use this service to remove task elements from a task queue and perform your own processing rather than using the QTI. (See Section 9.6 for more information on using the QTI.)

The ACMS$DEQUEUE_TASK service:

- Dequeues, or optionally reads, a queued task element from a queue and returns information about the queued task
- Does not dequeue queued task elements that are on hold (except by element ID)
- Deletes a queue element immediately upon removing it from the queue (unless the ACMS$DEQUEUE_TASK service is called with the READ_ONLY flag)

You can dequeue tasks by highest priority (first-in-first-out within priority), by element ID, or sequentially. See ACMS$DEQUEUE_TASK for the list of parameters that you can include on the ACMS$DEQUEUE_TASK service. See Section 9.7 for an example of a procedure that uses the ACMS$DEQUEUE_TASK service to process error queues.

# 9.6 Using the QTI to Dequeue Tasks

The ACMS QTI (Queued Task Initiator) is a run-time component that concurrently dequeues task elements from one or more queues and invokes the specified task in an ACMS application. The QTI is an ACMS-supplied Systems Interface (SI) agent program that automatically dequeues queued task elements that were queued by the ACMS$QUEUE_TASK service. You use the ACMS operator commands to start and stop the QTI, and to control the queues that are processed by the QTI.

You can start only one QTI process for each node on a cluster, but each QTI process can access multiple task queues anywhere on the same cluster. Multiple QTI processes can access the same task queues and error queues.

The QTI initiates processing of a queue by assigning an execution thread to the queue. An execution thread is a run-time entity which loops to do the processing described in the following list. The QTI is multithreaded, that is, it can execute many tasks (task threads) simultaneously. You can specify up to 255 task threads for a queue when you use the ACMS/START QUEUE command or the ACMS/SET QUEUE/TASK_THREADS command.

Specifying more execution threads for a queue increases the rate at which queued task elements are processed by performing the processing in parallel; the throughput for a queue increases with the number of execution threads. By assigning different numbers of execution threads to different queues, you can prioritize or weight several queues relative to one another. Normally, relatively small numbers (1 to 5) of task threads are sufficient.

Each execution thread of the QTI processes a queued task element in the following order:

1. If the task queue file is marked for recovery unit journaling, the QTI starts a distributed transaction.
2. Reads and locks the queued task element.
3. If the QTI has the agent privilege and has not already signed in the enqueuer user name, the QTI executes the systems interface ACMS$SIGN_IN service to sign in the submitter. If the QTI does not have the agent privilege, the submitter user name is the user name of the QTI process. You assign the agent privilege through the ACMS User Definition Utility (UDU).
4. Performs the systems interface ACMS$GET_PROCEDURE_INFO, ACMS$START_CALL, and ACMS$WAIT_FOR_CALL_END services to process the task in an ACMS application.
5. If the task completes successfully, the QTI deletes the queued task element from the queue and ends the distributed transaction. If the task fails, the QTI either places the element on hold so it can retry it later, places the task on an error queue (if one was specified), or deletes the element from the task queue (if it cannot be retried and an error queue was not specified).
6. When the queue is empty, the execution thread suspends processing until another queued task element is queued.

See Compaq ACMS for OpenVMS Managing Applications for more information about the ACMS operator commands you use to manage the QTI.

## 9.6.1 Characteristics of Queued Tasks That are Processed by the QTI

When you write a task that will be invoked by the QTI, you must write the task so that it abides by the following characteristics:

- The task cannot perform any exchange I/O. You must explicitly use the block phrase WITH NO I/O in the task definition. Because the task has no I/O, the ACMS$TASK_SUBMITTER_DEVICE field of the ACMS$TASK_INFORMATION workspace contains spaces at task execution time.
- The task must be composable if it is to participate in a distributed transaction. Section 9.2 describes how to make a task composable. The task queue file must be marked for recovery-unit journaling.
- You must define any input data needed by the task as task workspace arguments. Pass these workspaces to the task through the ACMS$QUEUE_TASK service. You must specify read access for the task workspace arguments being passed to the task.
- The task cannot assume any context in user or group workspaces as a result of previous tasks having executed. Tasks that are queued in a particular order might not be processed in the same order that they were submitted to the queue; therefore, a task invoked by the QTI should not assume context from tasks that are expected to run earlier. The following are some reasons why the order of the invocation of tasks might be different from the order that the queued tasks were queued:
  - Some queued task elements were placed on hold while others were not.
  - A task queue was suspended while another was not.
  - A queued task failed (for example, workspace pool exhausted) but before being retried by the QTI, other queued tasks ran successfully.
  - Some queued task elements were higher or lower priority.
- The ACMS$SELECTION_STRING workspace contains the queued task element ID in binary format. A queued task element ID is generated for each queued task element. The element ID is unique for all time and space.

## 9.6.2 Setting ACMSGEN Parameters for the QTI Process

Table 9-1 shows the ACMSGEN parameters that are associated with the QTI process.

Table 9-1 ACMSGEN Parameters Associated with QTI
Parameter Name | Default | Range | Dynamic
--- | --- | --- | ---
QTI_POLLING_TIMER | 5000 | 1 through --1 milliseconds | Yes
QTI_PRIORITY | 4 | 0 through 31 | No
QTI_SUB_TIMEOUT | 7200 | 1 through --1 seconds | Yes
QTI_RETRY_TIMER | 1800 | 1 through --1 seconds | Yes
QTI_USERNAME | SYSTEM | None | No

The next sections briefly explain these parameters. For more detail, see Compaq ACMS for OpenVMS Managing Applications.

### 9.6.2.1 Assigning a User Name to the QTI Process

You use the ACMSGEN parameter QTI_USERNAME to assign a user name to the QTI process. Be sure that the user name you assign has the SYSPRV and SYSLCK privileges. SYSPRV is needed for the QTI process in order to dequeue tasks from task queues. SYSLCK is needed for the QTI process to use the OpenVMS lock manager. See Compaq ACMS for OpenVMS Managing Applications for information on setting up the user name of the QTI.

If the user name of the QTI has been defined with ACMS agent privilege in the User Definition Utility (UDU) user authorization file, then the QTI submits tasks under the enqueuer user name. (See Section 9.5.1 for more information about the enqueuer user name.) If the user name of the QTI does not have the ACMS agent privilege, then QTI submits tasks under the QTI user name.

See Compaq ACMS for OpenVMS Managing Applications for information about assigning the agent privilege.

### 9.6.2.2 Assigning a Priority to the QTI Process

You use the ACMSGEN parameter QTI_PRIORITY to assign an OpenVMS priority to the QTI process.

### 9.6.2.3 Controlling Submitter Sign-Ins

The QTI is an ACMS Systems Interface (SI) agent program. As with all agent programs, the QTI uses the ACMS$SIGN_IN service to sign in a submitter before invoking a task on behalf of that submitter. Normally, an agent program determines when to sign out a submitter based on some submitter action. For example, the submitter might type "LOGOUT". However, the submitters being handled by the QTI are not active users who interact with the ACMS system (they are simply queued task elements). Therefore, the QTI leaves submitters signed in for a specified interval of time.

Because each submitter that is signed in to ACMS consumes memory resources, the QTI process uses a mechanism that enables it to bypass a submitter sign-in for each task. When the QTI process dequeues a queued task element, it checks the user name of that element. If it is the first time it has dequeued an element with that user name, it signs it in to ACMS but it does not sign out of ACMS when the task ends. Instead, it leaves the submitter signed in for a certain amount of time before signing it out. Consequently, if another queue element with the same user name is dequeued, the user name is already signed in.

You use the ACMSGEN parameter QTI_SUB_TIMEOUT to indicate how long a submitter can remain inactive before the QTI process signs that submitter out of ACMS. To determine how many submitters are signed in under a QTI process, use the ACMS/SHOW QTI command (see Compaq ACMS for OpenVMS Managing Applications for more information on operator commands).

Previous | Next | Contents | Index