This topic includes the following sections:
This topic deals with the use of the ATMI C language functions for enqueuing and dequeuing messages: tpenqueue(3c) and tpdequeue(3c), plus some ancillary functions.
The BEA Tuxedo programmer coding client or server programs for the queued message facility should be familiar with the C language binding to the BEA Tuxedo ATMI. General guidance on BEA Tuxedo programming is available in Programming BEA Tuxedo ATMI Applications Using C. Detailed pages on all the ATMI functions are in the BEA Tuxedo ATMI C Function Reference.
The calls used to place a message on a BEA Tuxedo /Q queue can originate from any client or server process associated with the application. The list includes:
The coverage of BEA Tuxedo /Q programming in this topic primarily reflects the left-hand portion of the figure Queued Service Invocation. In the figure, a client (or a process acting in the role of a client) queues a message by calling tpenqueue(3c) and specifying a queue space made available through a TMQUEUE(5) server. The client later retrieves a reply via a tpdequeue(3c) call to TMQUEUE
.
The figure Queued Service Invocation shows the queued message being dequeued by the server TMQFORWARD(5) and sent to an application server for processing (via tpcall(3c)). When a reply to the tpcall()
is received, TMQFORWARD
enqueues the reply message. Because a major goal of TMQFORWARD
is to provide an interface between the queue space and existing application services, it does not require further application coding. For that reason, this topic concentrates on the client-to-queue space side.
A brief example of the use of the queued message facility is distributed with the software and is described in A Sample Application.
The syntax for tpenqueue()
is as follows:
#include <atmi.h>
int tpenqueue(char *qspace
, char *qname
, TPQCTL *ctl
,
char *data
, longlen
, longflags
)
When a tpenqueue()
call is issued, it tells the system to store a message on the queue identified in qname
in the space identified in qspace
. The message is in the buffer pointed to by data
and has a length of len
. By the use of bit settings in flags
, the system is informed how the call to tpenqueue()
is to be handled. Further information about the handling of the enqueued message and replies is provided in the TMQCTL
structure pointed to by ctl
.
There are some important arguments to control the operation of tpenqueue(3c). Let's look at some of them.
qspace
identifies a queue space previously created by the administrator. When a server is defined in the SERVERS
section of the configuration file, the service names it offers are aliases for the actual queue space name (which is specified as part of the OPENINFO
parameter in the GROUPS
section). For example, when your application uses the server TMQUEUE
, the value pointed at by the qspace
argument is the name of a service advertised by TMQUEUE
. If no service aliases are defined, the default service is the same as the server name, TMQUEUE
. In this case the configuration file might include:
TMQUEUE
SRVGRP = QUE1 SRVID = 1
GRACE = 0 RESTART = Y CONV = N
CLOPT = "-A"
CLOPT = "-s TMQUEUE"
The entry for server group QUE1
has an OPENINFO
parameter that specifies the resource manager, the pathname of the device and the queue space name. The qspace
argument in a client program then looks like this:
if (tpenqueue("TMQUEUE", "STRING", (TPQCTL *)&qctl,
(char *)reqstr, 0,0) == -1) {
Error checking
}
The example shown on the TMQUEUE(5) reference page shows how alias service names can be included when the server is built and specified in the configuration file. The sample program in A Sample Application, also specifies an alias service name.
Within a queue space, when queues are being used to invoke services, message queues are named according to the application services available to process requests. qname
is a pointer to such an application service. Otherwise, qname
is simply the name of the location where the message is to be stored until it is dequeued by an application (either the same application that enqueued it or another one).
data
points to a buffer that contains the message to be processed. The buffer must be one that was allocated with a call to tpalloc(3c). len
gives the length of the message. Some BEA Tuxedo buffer types (such as FML) do not require that the length of the message be specified; in such cases, the len
argument is ignored. data
can be NULL; when it is, len
is ignored and the message is enqueued with no data portion.
flags
values are used to tell the BEA Tuxedo system how the tpenqueue()
call is handled; the following are valid flags:
TPNOTRAN
TPNOBLOCK
TPEBLOCK
. If this flag is set and a blocking condition exists because the target queue is opened exclusively by another application, the call fails, tperrno()
is set to TPEDIAGNOSTIC
, and the diagnostic field of the TPQCTL
structure is set to QMESHARE
. In the latter case, the other application, which is based on a BEA product other than the BEA Tuxedo system, opened the queue for exclusive read and/or write using the Queuing Services API (QSAPI).
TPNOBLOCK
is not set and a blocking condition exists, the caller blocks until the condition subsides or a timeout occurs (either transaction or blocking timeout). If a timeout occurs, the call fails and tperrno()
is set to TPETIME
.
TPNOTIME
TPSIGRSTRT
TPGOTSIG
.
The third argument to tpenqueue()
is a pointer to a structure of type TPQCTL
. The TPQCTL
structure has members that are used by the application and by the BEA Tuxedo system to pass parameters in both directions between application programs and the queued message facility. The client that calls tpenqueue()
sets flags to mark fields the application wants the system to fill in. The structure is also used by tpdequeue()
; some of the fields do not come into play until the application calls that function. The complete structure is shown in the following listing.
#define TMQNAMELEN 15
#define TMMSGIDLEN 32
#define TMCORRIDLEN 32
struct tpqctl_t { /* control parameters to queue primitives */
long flags; /* indicates which of the values are set */
long deq_time; /* absolute/relative time for dequeuing */
long priority; /* enqueue priority */
long diagnostic; /* indicates reason for failure */
char msgid[TMMSGIDLEN]; /* ID of message before which to queue */
char corrid[TMCORRIDLEN]; /* correlation ID used to identify message */
char replyqueue[TMQNAMELEN+1]; /* queue name for reply message */
char failurequeue[TMQNAMELEN+1]; /* queue name for failure message */
CLIENTID cltid; /* client identifier for originating client */
long urcode; /* application user-return code */
long appkey; /* application authentication client key */
long delivery_qos; /* delivery quality of service */
long reply_qos; /* reply message quality of service */
long exp_time; /* expiration time */
};
typedef struct tpqctl_t TPQCTL;
The following is a list of valid bits for the flags
parameter controlling input information for tpenqueue()
.
TPNOFLAGS
TPNOFLAGS
.
TPQTOP
TPQTOP
and TPQBEFOREMSGID
are mutually exclusive flags
TPQBEFOREMSGID
ctl->msgid
. This request may not be granted depending on whether or not the queue was configured to allow overriding the queue ordering. TPQTOP
and TPQBEFOREMSGID
are mutually exclusive flags. Note that the entire 32 bytes of the message identifier value are significant, so the value identified by ctl->msgid
must be completely initialized (for example, padded with NULL characters).
TPQTIME_ABS
ctl->deq_time
. The deq_time
is an absolute time value as generated by time(2)
or mktime(3C)
, if they are available to your application, or gp_mktime(3c), provided with the BEA Tuxedo system. The value set in ctl->deq_time
is the number of seconds since 00:00:00 Universal Coordinated Time—UTC, January 1,1970. The absolute time is set based on the clock on the machine where the queue manager process resides. TPQTIME_ABS
and TPQTIME_REL
are mutually exclusive flags.
TPQTIME_REL
ctl->deq_time
specifies the number of seconds to delay after the enqueuing completes before the submitted message should be available. TPQTIME_ABS
and TPQTIME_REL
are mutually exclusive flags.
TPQPRIORITY
ctl->priority
. The priority must be in the range 1 to 100, inclusive. The higher the number, the higher the priority, that is, a message with a higher number is dequeued before a message with a lower number from queues ordered by priority. For queues not ordered by priority, the value is informational.
TPQCORRID
ctl->corrid
is available when a request is dequeued with tpdequeue(3c). This identifier accompanies any reply or failure message that is queued so an application can correlate a reply with a particular request. Note that the entire 32 bytes of the correlation identifier value are significant, so the value specified in ctl->corrid
must be completely initialized (for example, padded with NULL characters).
TPQREPLYQ
ctl->replyqueue
is associated with the queued message. Any reply to the message is queued to the named queue within the same queue space as the request message. This string must be NULL-terminated (maximum 15 characters in length). If a reply is generated for the service and a reply queue is not specified or the reply queue does not exist, the reply is dropped.
TPQFAILUREQ
ctl->failurequeue
is associated with the queued message. If (1) the enqueued message is processed by TMQFORWARD()
, (2) TMQFORWARD
was started with the -d
option, and (3) the service fails and returns a non-NULL reply, a failure message consisting of the reply and its associated tpurcode
is enqueued to the named queue within the same queue space as the original request message. This string must be NULL-terminated (maximum 15 characters in length).
TPQDELIVERYQOS
, TPQREPLYQOS
TPQDELIVERYQOS
flag is set, the flags specified by ctl->delivery_qos
control the quality of service for delivery of the message. In this case, one of three mutually exclusive flags— TPQQOSDEFAULTPERSIST
, TPQQOSPERSISTENT
, or TPQQOSNONPERSISTENT
—must be set in ctl->delivery_qos
. If TPQDELIVERYQOS
is not set, the default delivery policy of the target queue dictates the delivery quality of service for the message.
TPQREPLYQOS
flag is set, the flags specified by ctl->reply_qos
control the quality of service for any reply to the message. In this case, one of three mutually exclusive flags—TPQQOSDEFAULTPERSIST
, TPQQOSPERSISTENT
, or TPQQOSNONPERSISTENT
—must be set in ctl->reply_qos
. The TPQREPLYQOS
flag is used when a reply is returned from messages processed by TMQFORWARD
. Applications not using TMQFORWARD
to invoke services may use the TPQREPLYQOS
flag as a hint for their own reply mechanism.
If TPQREPLYQOS is not set, the default delivery policy of the ctl->replyqueue
queue dictates the delivery quality of service for any reply. Note that the default delivery policy is determined when the reply to a message is enqueued. That is, if the default delivery policy of the reply queue is modified between the time that the original message is enqueued and the reply to the message is enqueued, the policy used is the one in effect when the reply is finally enqueued.
The following is the list of valid flags for ctl->delivery_qos
and ctl->reply_qos
:
TPQEXPTIME_ABS
ctl->exp_time
. The value of ctl->exp_time
must be set to an absolute time value generated by time(2)
, mktime(3C)
, or gp_mktime(3c) (the number of seconds since 00:00:00 Universal Coordinated Time—UTC, January 1, 1970).
If an absolute time is specified that is earlier than the time of the enqueue operation, the operation succeeds, but the message is not counted for the purpose of calculating thresholds. If the expiration time is before the message availability time, the message is not available for dequeuing unless either the availability or expiration time is changed so that the availability time is before the expiration time. In addition, these messages are removed from the queue at expiration time even if they were never available for dequeuing. If a message expires while it is within a transaction, the expiration does not cause the transaction to fail. Messages that expire while being enqueued or dequeued within a transaction are removed from the queue when the transaction ends. There is no notification that the message has expired.
TPQEXPTIME_ABS
, TPQEXPTIME_REL
, and TPQEXPTIME_NONE
are mutually exclusive flags. If none of these flags is set, the default expiration time associated with the target queue is applied to the message.
TPQEXPTIME_REL
ctl->exp_time
.
TPQEXPTIME_ABS
, TPQEXPTIME_REL
, and TPQEXPTIME_NONE
are mutually exclusive flags. If none of these flags is set, the default expiration time associated with the target queue is applied to the message.
TPQEXPTIME_NONE
TPQEXPTIME_ABS
, TPQEXPTIME_REL
, and TPQEXPTIME_NONE
are mutually exclusive flags. If none of these flags is set, the default expiration time associated with the target queue is applied to the message.
Additionally, the urcode
field of TPQCTL
can be set with a user-return code. This value will be returned to the application that calls tpdequeue(3c) to dequeue the message.
On output from tpenqueue()
, the following fields may be set in the TPQCTL
structure:
long flags; /* indicates which of the values are set */
char msgid[32]; /* ID of enqueued message */
long diagnostic; /* indicates reason for failure */
The following is a valid bit for the flags
parameter controlling output information from tpenqueue()
. If this flag is turned on when tpenqueue()
is called, the /Q server TMQUEUE(5) populates the associated element in the structure with a message identifier. If this flag is turned off when tpenqueue()
is called, TMQUEUE()
does not populate the associated element in the structure with a message identifier.
TPQMSGID
tpenqueue()
is successful, the message identifier is stored in ctl->msgid
. The entire 32 bytes of the message identifier value are significant, so the value stored in ctl->msgid
is completely initialized (for example, padded with null characters). The actual padding character used for initialization varies between releases of the BEA Tuxedo /Q component.
The remaining members of the control structure are not used on input to tpenqueue()
.
If the call to tpenqueue()
fails and tperrno(5) is set to TPEDIAGNOSTIC
, a value indicating the reason for failure is returned in ctl->diagnostic
. The possible values are:
QMEINVAL
]
QMEBADRMID
]
QMENOTOPEN
]
QMETRAN
]
TPNOTRAN
flag set and an error occurred trying to start a transaction in which to enqueue the message. This diagnostic is not returned by queue managers from BEA Tuxedo release 7.1 or later.
QMEBADMSGID
]
QMESYSTEM
]
QMEOS
]
QMEABORTED
]
QMEPROTO
]
QMEBADQUEUE
]
QMENOSPACE
]
QMENOSPACE
is returned when any of the following configured resources is exceeded: (1) the amount of disk (persistent) space allotted to the queue space, (2) the amount of memory (non-persistent) space allotted to the queue space, (3) the maximum number of simultaneously active transactions allowed for the queue space, (4) the maximum number of messages that the queue space can contain at any one time, (5) the maximum number of concurrent actions that the Queuing Services component can handle, or (6) the maximum number of authenticated users that may concurrently use the Queuing Services component.
QMERELEASE
]
QMESHARE
]
If the administrator, in creating a queue, allows tpenqueue()
calls to override the order of messages on the queue, you have two mutually exclusive ways to use that capability. You can specify that the message is to be placed at the top of the queue by setting flags
to include TPQTOP
or you can specify that it be placed ahead of a specific message by setting flags
to include TPQBEFOREMSGID
and setting ctl->msgid
to the ID of the message you wish to precede. This assumes that you saved the message-ID from a previous call in order to be able to use it here. Your administrator must tell you what the queue supports; it can be created to allow either or both of these overrides, or to allow neither.
You can set a value in ctl->priority
to specify the priority of the message. The value must be in the range 1 to 100; the higher the number the higher the priority. If priority
was not one of the queue ordering parameters, setting a priority here has no effect on the dequeuing order, however the priority value is retained so that the value can be inspected when the message is dequeued.
You can specify in deq_time
either an absolute time or a time relative to the completion of the enqueuing operation for the message to be made available. You set flags
to include either TPQTIME_ABS
or TPQTIME_REL
to indicate how the value should be treated. A queue may be created with time
as a queue ordering criterion, in which case the messages are ordered by the message availability time.
BEA Tuxedo /Q provides a function, gp_mktime(3c), that is used to convert a date and time provided in a tm
structure to the number of seconds since January 1, 1970. The time
(2) and mktime
(3C) functions may also be used instead of gp_mktime
(3c). The value is returned in time_t
, a typedef'd
long. To set an absolute time for the message to be dequeued (we are using 12:00 noon, December 9, 2001), do the following.
tm
structure.#include <stdio.h>
#include <time.h>
static char *const wday[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday", "-unknown-"
};
struct tm time_str;
/*...*/
time_str.tm_year = 2001 - 1900;
time_str.tm_mon = 12 - 1;
time_str.tm_mday = 9;
time_str.tm_hour = 12;
time_str.tm_min = 0;
time_str.tm_sec = 1;
time_str.tm_isdst = -1;
gp_mktime
to produce a value for deq_time
and set the flags
to indicate that an absolute time is being provided. #include <atmi.h>
TPQCTL qctl;
if ((qctl->deq_time = (long)gp_mktime(&time_str)) == -1) {
/* check for errors */
}
qctl->flags = TPQTIME_ABS
tpenqueue()
.if (tpenqueue(qspace, qname, qctl, *data,*len,*flags) == -1) {
/* check for errors */
}
If you want to specify a relative time for dequeuing, for example, nnn
seconds after the completion of the enqueuing operation, place the number of seconds in deq_time
and set flags
to include TPQTIME_REL
.
If a caller of tpenqueue()
is in transaction mode and TPNOTRAN
is not set, then the enqueuing is done within the caller's transaction. The caller knows for certain from the success or failure of tpenqueue()
whether the message was enqueued or not. If the call succeeds, the message is guaranteed to be on the queue. If the call fails, the transaction is rolled back, including the part where the message was placed on the queue.
If a caller of tpenqueue()
is not in transaction mode or if TPNOTRAN
is set, the message is enqueued outside of the caller's transaction. If the call to tpenqueue()
returns success, the message is guaranteed to be on the queue. If the call to tpenqueue()
fails with a communication error or with a timeout, the caller is left in doubt about whether the failure occurred before or after the message was enqueued.
Note that specifying TPNOTRAN
while the caller is not in transaction mode has no meaning.
The syntax for tpdequeue()
is as follows:
#include <atmi.h>
int tpdequeue(char *qspace, char *qname, TPQCTL *ctl, \
char **data, long *len, long flags)
When this call is issued it tells the system to dequeue a message from the qname
queue in the queue space named qspace
. The message is placed in a buffer (originally allocated by tpalloc(3c)) at the address pointed to by *data
. len
points to the length of the data. If len
is 0 on return from tpdequeue()
, the message had no data portion. By the use of bit settings in flags
, the system is informed how the call to tpdequeue()
is to be handled. The TPQCTL
structure pointed to by ctl
carries further information about how the call should be handled.
There are some important arguments to control the operation of tpdequeue(3c). Let's look at some of them.
qspace
identifies a queue space previously created by the administrator. When the TMQUEUE
server is defined in the SERVERS
section of the configuration file, the service names it offers are aliases for the actual queue space name (which is specified as part of the OPENINFO
parameter in the GROUPS
section). For example, when your application uses the server TMQUEUE
, the value pointed at by the qspace
argument is the name of a service advertised by TMQUEUE
. If no service aliases are defined, the default service is the same as the server name, TMQUEUE
. In this case the configuration file may include:
TMQUEUE
SRVGRP = QUE1 SRVID = 1
GRACE = 0 RESTART = Y CONV = N
CLOPT = "-A"
or
CLOPT = "-s TMQUEUE"
The entry for server group QUE1
has an OPENINFO
parameter that specifies the resource manager, the pathname of the device and the queue space name. The qspace
argument in a client program then looks like this:
if (tpdequeue("TMQUEUE", "REPLYQ", (TPQCTL *)&qctl,
(char **)&reqstr, &len,TPNOTIME) == -1) {
Error checking
}
The example shown on the TMQUEUE(5) reference page shows how alias service names can be included when the server is built and specified in the configuration file. The sample program in A Sample Application, also specifies an alias service/queue space name.
Queue names in a queue space must be agreed upon by the applications that will access the queue space. This is especially important for reply queues. If qname
refers to a reply queue, the administrator creates it (and often an error queue) in the same manner that he or she creates any other queue. qname
is a pointer to the name of the queue from which to retrieve the message or reply.
These arguments have slightly different meanings than their counterparts in tpenqueue()
. *data
points to the address of a buffer where the system is to place the message being dequeued. When tpdequeue()
is called, it is an error for its value to be NULL.
When tpdequeue()
returns, len
points to a value of type long
that carries information about the length of the data retrieved. If it is 0, it means that the reply had no data portion. This can be a legitimate and successful reply in some applications; receiving even a 0 length reply can be used to show successful processing of the enqueued request. If you wish to know whether the buffer has changed from before the call to tpdequeue()
, save the length prior to the call to tpdequeue()
and compare it to len
after the call completes.
flags
values are used to tell the BEA Tuxedo system how the tpdequeue()
call is handled; the following are valid flags:
TPNOTRAN
TPNOBLOCK
TPEBLOCK
. If this flag is set and a blocking condition exists because the target queue is opened exclusively by another application, the call fails, tperrno()
is set to TPEDIAGNOSTIC
, and the diagnostic field of the TPQCTL
structure is set to QMESHARE
. In the latter case, the other application, which is based on a BEA product other than the BEA Tuxedo system, opened the queue for exclusive read and/or write using the Queuing Services API (QSAPI).
TPNOBLOCK
is not set and a blocking condition exists, the caller blocks until the condition subsides or a timeout occurs (either transaction or blocking timeout). This blocking condition does not include blocking on the queue itself if the TPQWAIT
option in flags
(of the TPQCTL
structure) is specified.
TPNOTIME
TPNOCHANGE
data
is not allowed to change. By default, if a buffer is received that differs in type from the buffer pointed to by *data
, then *data
's buffer type changes to the received buffer's type so long as the receiver recognizes the incoming buffer type. That is, the type and subtype of the received buffer must match the type and subtype of the buffer pointed to by *data
.
TPSIGRSTRT
TPGOTSIG
.
The third argument to tpdequeue()
is a pointer to a structure of type TPQCTL
. The TPQCTL
structure has members that are used by the application and by the BEA Tuxedo system to pass parameters in both directions between application programs and the queued message facility. The client that calls tpdequeue()
sets flags to mark fields for which the system should supply values. As described earlier, the structure is also used by tpenqueue()
; some of the members apply only to that function. The entire structure is shown in The tpqctl_t Structure.
As input to tpdequeue()
, the following fields may be set in the TPQCTL
structure:
long flags; /* indicates which of the values are set */
char msgid[32]; /* id of message to dequeue */
char corrid[32]; /* correlation identifier of message to dequeue */
The following are valid flags on input to tpdequeue()
:
TPNOFLAGS
TPQGETBYMSGID
ctl->msgid
be dequeued. The message identifier is determined through a prior call to tpenqueue()
. Note that the message identifier changes if the message is moved from one queue to another. Note also that the entire 32 bytes of the message identifier value are significant, so the value specified by ctl->msgid
must be completely initialized (for example, padded with null characters).
TPQGETBYCORRID
ctl->corrid
be dequeued. The correlation identifier is specified by the application when enqueuing the message with tpenqueue()
. Note that the entire 32 bytes of the correlation identifier value are significant, so the value specified by ctl->corrid
must be completely initialized (for example, padded with null characters).
TPQWAIT
TPQWAIT
is set in conjunction with TPQGETBYMSGID
or TPQGETBYCORRID
, it indicates that an error should not be returned if no message with the specified message identifier or correlation identifier is present in the queue. Instead, the process should wait until a message meeting the criteria is available. The process is still subject to the caller's transaction timeout, or, when not in transaction mode, the process is still subject to the timeout specified for the TMQUEUE
process by the -t
option.
tpdequeue()
returns -1, tperrno()
is set to TPEDIAGNOSTIC
, and the diagnostic field of the TPQCTL
structure is set to QMESYSTEM
.
Note that each tpdequeue()
request specifying the TPQWAIT
control parameter requires that a queue manager (TMQUEUE
) action object be available if a message satisfying the condition is not immediately available. If an action object is not available, the tpdequeue()
request fails. The number of available queue manager actions are specified when a queue space is created or modified. When a waiting dequeue request completes, the associated action object associated is made available for another request.
TPQPEEK
TPNOTRAN
flag must also be set.
TPQPEEK
, the message may not be seen by other non-blocking dequeuers for the brief time the system is processing the non-destructive dequeue request. This includes dequeuers using specific selection criteria (such as message identifier and correlation identifier) that are looking for the message currently being non-destructively dequeued.
The following is a list of valid bits for the flags
parameter controlling output information from tpdequeue()
. For any of these bits, if the flag bit is turned on when tpdequeue()
is called, the associated field in the structure (see The tpqctl_t Structure) is populated with the value provided when the message was queued, and the bit remains set. If a value is not available (that is, no value was provided when the message was queued) or the bit is not set when tpdequeue()
is called, tpdequeue()
completes with the flag turned off.
TPQPRIORITY
tpdequeue()
is successful, and the message was queued with an explicit priority, then the priority is stored in ctl->priority
. The priority is in the range 1 to 100, inclusive, and the higher the number, the higher the priority (that is, a message with a higher number is dequeued before a message with a lower number). For queues not ordered by priority, the value is informational.
tpdequeue()
is successful, the priority for the message is 50.
TPQMSGID
tpdequeue()
is successful, the message identifier is stored in ctl->msgid
. The entire 32 bytes of the message identifier value are significant.
TPQCORRID
tpdequeue()
is successful, and the message was queued with a correlation identifier, then the correlation identifier is stored in ctl->corrid
. The entire 32 bytes of the correlation identifier value are significant. Any BEA Tuxedo /Q provided reply to a message has the correlation identifier of the original request message.
TPQDELIVERYQOS
tpdequeue()
is successful, and the message was queued with a delivery quality of service, then the flag—TPQQOSDEFAULTPERSIST
, TPQQOSPERSISTENT
, or TPQQOSNONPERSISTENT
—is stored in ctl->delivery_qos
. If no delivery quality of service was explicitly specified when the message was queued, the default delivery policy of the target queue dictates the delivery quality of service for the message.
TPQREPLYQOS
tpdequeue()
is successful, and the message was queued with a reply quality of service, then the flag—TPQQOSDEFAULTPERSIST
, TPQQOSPERSISTENT
, or TPQQOSNONPERSISTENT
—is stored in ctl->reply_qos
. If no reply quality of service was explicitly specified when the message was queued, the default delivery policy of the ctl->replyqueue
queue dictates the delivery quality of service for any reply.
TPQREPLYQ
tpdequeue()
is successful, and the message was queued with a reply queue, then the name of the reply queue is stored in ctl->replyqueue
. Any reply to the message should go to the named reply queue within the same queue space as the request message.
TPQFAILUREQ
tpdequeue()
is successful, and the message was queued with a failure queue, then the name of the failure queue is stored in ctl->failurequeue
. Any failure message should go to the named failure queue within the same queue space as the request message.
The following remaining bits for the flags
parameter are cleared (set to zero) when tpdequeue()
is called: TPQTOP
, TPQBEFOREMSGID
, TPQTIME_ABS
, TPQTIME_REL
, TPQEXPTIME_ABS
, TPQEXPTIME_REL
, and TPQEXPTIME_NONE
. These bits are valid bits for the flags
parameter controlling input information for tpenqueue()
.
If the call to tpdequeue()
failed and tperrno(5) is set to TPEDIAGNOSTIC
, a value indicating the reason for failure is returned in ctl->diagnostic
. The valid codes for ctl->diagnostic
include those for tpenqueue()
described in TPQCTL Structure (except for QMENOSPACE
and QMERELEASE
) and the following additional codes.
QMENOMSG
]
QMEINUSE
]
When tpdequeue()
is called with flags
(of the TPQCTL
structure) set to include TPQWAIT
, if a message is not immediately available, the TMQUEUE
server waits for the arrival, on the queue, of a message that matches the tpdequeue()
request before tpdequeue()
returns control to the caller. The TMQUEUE
process sets the waiting request aside and processes requests from other processes while waiting to satisfy the first request. If TPQGETBYMSGID
and/or TPQGETBYCORRID
are also specified, the server waits until a message with the indicated message identifier and/or correlation identifier becomes available on the queue. If neither of these flags is set, the server waits until any message is put onto the queue. The amount of time it waits is controlled by the caller's transaction timeout, if the call is in transaction mode, or by the -t
option in the CLOPT
parameter of the TMQUEUE
server, if the call is not in transaction mode.
The TMQUEUE
server can handle a number of waiting tpdequeue()
requests at the same time, as long as action resources are available to handle the request. If there are not enough action resources configured for the queue space, tpdequeue()
fails. If this happens on your system, increase the number of action resources for the queue space.
In considering how best to handle errors when dequeuing it is helpful to differentiate between two types of errors:
By default, if a message is dequeued within a transaction and the transaction is rolled back, then (if the retry
parameter is greater than 0) the message ends up back on the queue and can be dequeued and executed again. It may be desirable to delay for a short period before retrying to dequeue and execute the message, allowing the transient problem to clear (for example, allowing for locks in a database to be released by another transaction). Normally, a limit on the number of retries is also useful to ensure that an application flaw doesn't cause significant waste of resources. When a queue is configured by the administrator, both a retry count and a delay period (in seconds) can be specified. A retry count of 0 implies that no retries are done. After the retry count is reached, the message is moved to an error queue that is configured by the administrator for the queue space. If the error queue is not configured, then messages that have reached the retry count are simply deleted. Messages on the error queue must be handled by the administrator who must work out a way of notifying the originator that meets the requirements of the application. The message handling method chosen should be mostly transparent to the originating program that put the message on the queue. There is a virtual guarantee that once a message is successfully enqueued it will be processed according to the parameters of tpenqueue()
and the attributes of the queue. Notification that a message has been moved to the error queue should be a rare occurrence in a system that has properly tuned its queue parameters.
A failure queue (normally, different from the queue space error queue) may be associated with each queued message. This queue is specified on the enqueuing call as the place to put any failure messages. The failure message for a particular request can be identified by an application-generated correlation identifier that is associated with the message when it is enqueued.
The default behavior of retrying until success (or a predefined limit) is quite appropriate when the failure is caused by a transient problem that is later resolved, allowing the message to be handled appropriately.
There are cases where the problem is not transient. For example, the queued message may request operating on an account that does not exist (and the application is such that it won't come into existence within a reasonable time period if at all). In this case, it is desirable not to waste any resources by trying again. If the application programmer or administrator determines that failures for a particular operation are never transient, then it is simply a matter of setting the retry count to zero, although this will require a mechanism to constantly clear the queue space error queue of these messages (for example, a background client that reads the queue periodically). More likely, it is the case that some problems will be transient (for example, database lock contention) and some problems will be permanent (for example, the account doesn't exist) for the same service.
In the case that the message is processed (dequeued and passed to the application via a tpcall()
) by TMQFORWARD
, there is no mechanism in the information returned by tpcall()
to indicate whether a TPESVCFAIL
error is caused by a transient or permanent problem.
As in the case where the application is handling the dequeuing, a simple solution is to return success for the service, that is, tpreturn
with TPSUCCESS
, even though the operation failed. This allows the transaction to be committed and the message removed from the queue. If reply messages are being used, the information in the buffer returned from the service can indicate that the operation failed and the message will be enqueued on the reply queue. The rcode
argument of tpreturn
can also be used to return application specific information.
In the case where the service fails and the transaction must be rolled back, it is not clear whether or not TMQFORWARD
should execute a second transaction to remove the message from the queue without further processing. By default, TMQFORWARD
will not delete a message for a service that fails. TMQFORWARD's
transaction is rolled back and the message is restored to the queue. A command-line option may be specified for TMQFORWARD
that indicates that a message should be deleted from the queue if the service fails and a reply message is sent back with length greater than 0. The message is deleted in a second transaction. The queue must be configured with a delay time and retry count for this to work. If the message is associated with a failure queue, the reply data will be enqueued to the failure queue in the same transaction as the one in which the message is deleted from the queue.
If your application expects to receive replies to queued messages, the following is a procedure you may want to follow:
TPSUCCESS
on a logical failure and return an explanatory code in the rcode
argument of tpreturn
. tpenqueue()
to put the message on the queue, set flags
to turn on the bits for the following flags: TPQCORRID TPQREPLYQ
TPQFAILUREQ TPQMSGID
Fill in the values for corrid
, replyqueue
and failurequeue
before issuing the call. On return from the call, save corrid
.
tpdequeue()
to check for a reply, specify the reply queue in the qname
argument and set flags
to turn on the bits for the following flags: TPQCORRID TPQREPLYQ
TPQFAILUREQ TPQMSGID
TPQGETCORRID
Use the saved correlation identifier to populate corrid
before issuing the call. If the call to tpdequeue()
fails and sets tperrno(5) to TPEDIAGNOSTIC
, then further information is available in diagnostic
. If you receive the error code QMENOMSG
, it means that no message was available for dequeuing.
tpdequeue()
. This time have qname
point to the name of the failure queue and set flags
to turn on the bits for the following flags: TPQCORRID TPQREPLYQ
TPQFAILUREQ TPQMSGID
TPQGETBYCORRID
Populate corrid
with the correlation identifier. When the call returns, check len
to see if data has been received and check urcode
to see if the service has returned a user return code.
Sequential processing of messages can be achieved by having one service enqueue a message for the next service in the chain before its transaction is committed. The originating process can track the progress of the sequence with a series of tpdequeue()
calls to the reply_queue
, if each member uses the same correlation-ID and returns a 0 length reply.
Alternatively, word of the successful completion of the entire sequence can be returned to the originator by using unsolicited notification. To make sure that the last transaction in the sequence ended with a tpcommit
, a job step can be added that calls tpnotify
using the client identifier that is carried in the TPQCTL
structure returned from tpdequeue()
or in the TPSVCINFO
structure passed to the service. The originating client must have called tpsetunsol
to name the unsolicited message handler being used.
In all of the foregoing discussion of enqueuing and dequeuing messages there has been an implicit assumption that queues were being used as an alternative form of request/response processing. A message does not have to be a service request. The queued message facility can transfer data from one process to another as effectively as a service request. This style of communication between applications or clients is called peer-to-peer communication.
If it suits your application to use BEA Tuxedo /Q for this purpose, have the administrator create a separate queue and code your own receiving program for dequeuing messages from that queue.