PubSub+ Messaging API For C  7.31.0.7
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
PubSub+ Messaging API For C Documentation

Introduction

The Messaging API for C provides an Application Programming Interface (API) for developing C or C++ applications for use with a Solace messaging broker.

Overview

The Messaging API for C (also referred to as SolClient) is specifically designed to provide high message throughput and low latency with the lowest CPU utilization possible. It is a fully functional API, and it contains the following main features:

  • Allows the application to connect to a Solace messaging broker through the concept of a "Session".
  • Allows messages to be constructed and sent on a Session and to be received from a Session.
  • Allows subscriptions to be added to specify what messages are to be received. Subscriptions are topic-based.
  • Support for Guaranteed Message delivery (Queue-based or Topic Endpoint-based). Guaranteed messages are received on "Flows" (see solClient_session_createFlow()), which are constructed within a Session. Guaranteed Messaging is only available to clients when a Solace messaging broker is used that has an Assured Delivery Blade (ADB) installed and Guaranteed Messaging and message spooling enabled.
  • Allows fine-tuning of API behavior, such as whether operations should be blocking or non-blocking in nature.
  • Allows for the option of application file descriptors to be monitored within the API, providing the application with callbacks for readable and writable events.
  • Allows for the option of the application taking over control of file descriptors created within the API to connect to the Solace messaging broker, where the application must provide readable and writable events to the API.
  • Support for timer services.
  • Support for logging, including support for logging filter levels, and the ability for the application to be called back for generated logs so that they can be placed into the application's logging system.

Messaging API for C Specifics

The Messaging API for C behavior is unique among Solace Corporation Messaging APIs in the following ways:

Threading Support

By default, the Messaging API for C does not provide any internal threads. Instead, the API allows the application to provide thread processing time, providing more flexibility to application designers on how to allocate messaging system resources. However, SolClient can optionally provide a Context thread for processing work that is suitable for the most common application models and architectures.

Blocking and Non-Blocking Modes

These modes are handled differently for the Messaging API for C than with the Messaging API for Java. For the Messaging API for C, blocking mode means that the calling thread for each send() function call is blocked until the API can accept the message. As a result, the application automatically controls the flow of send() calls to a rate at which the broker can accept them. The send() function call remains blocked until either it is accepted by the API, or the timer (specified by SOLCLIENT_SESSION_PROP_BLOCKING_WRITE_TIMEOUT_MS) expires.

In non-blocking mode, send() function calls that cannot be accepted by the API immediately return a solClient_returnCode SOLCLIENT_WOULD_BLOCK error code to the application. If the application receives a SOLCLIENT_WOULD_BLOCK error, then it also receive a subsequent SOLCLIENT_SESSION_EVENT_CAN_SEND event. The application can then retry the send() function call. In the interim, it can continue to process other actions.

Threading Effects on Blocking Modes

The thread that is responsible for calling solClient_context_processEvents() is commonly referred to as the Context thread. Whether this thread is provided by SolClient, or a separate application thread, there are blocking implications that the application developer must be aware of. All callbacks from the API to the application, message receive callbacks, event callback, and timer callbacks, run from the Context thread. Additionally the Context thread must run to detect relief from flow control and unblock waiting application threads. The Context thread must run to complete the Session connection sequence and unblock applications waiting for connection complete. The Context thread must run to unblock applications waiting for confirmation on subscription requests.

Consequently, applications must not block in callback routines. Waiting in callback routines can deadlock the application or at a minimum severely degrade receive performance. Deferring SolClient processing by running for excessively long periods of time in the callback routines will prevent SolClient from unblocking other application threads that might be waiting for confirmation of sent messages or be blocked in flow control situations.

SolClient detects when an application re-enters the API from a callback and will never block. Consequently, applications can expect to see SOLCLIENT_FAIL return codes when making SolClient function calls from a callback routine, if the function call would be blocking in other threads. Generally, if a function could block because of TCP flow control, SOLCLIENT_FAIL is returned when that function is called from a callback, if the Session property SOLCLIENT_SESSION_PROP_SEND_BLOCKING is enabled. This will only occur if the session finds it is flow controlled at the socket (TCP). If it is possible to send the message, the function call will succeed as usual. If the Session property SOLCLIENT_SESSION_PROP_SEND_BLOCKING is disabled, the API will succeed or return SOLCLIENT_WOULD_BLOCK as expected.

Further, if the application explicitly sets SOLCLIENT_SUBSCRIBE_FLAGS_WAITFORCONFIRM on a subscribe or unsubscribe API call made from a callback routine, that function call will return SOLCLIENT_FAIL and set the subcode to SOLCLIENT_SUBCODE_CANNOT_BLOCK_IN_CONTEXT. Similarly, a function call on modifyClientInfo API made from a callback will return SOLCLIENT_FAIL (with the subcode SOLCLIENT_SUBCODE_CANNOT_BLOCK_IN_CONTEXT) when the flag SOLCLIENT_MODIFYPROP_FLAGS_WAITFORCONFIRM is set explicitly by the application.

Message Buffer Size Configuration

The Session buffer size configured using the SOLCLIENT_SESSION_PROP_BUFFER_SIZE Session property controls SolClient buffering of transmit messages. When sending small messages, to improve the performance, the Session buffer size should be set to multiple times the typical message size. Regardless of the buffer size, SolClient always accepts at least one message to transmit. So even if a single message exceeds SOLCLIENT_SESSION_PROP_BUFFER_SIZE, it is accepted and transmitted as long as the current buffered data is zero. However no more messages are accepted until the amount of data buffered is reduced enough to allow room below SOLCLIENT_SESSION_PROP_BUFFER_SIZE.

SolClient will internally buffer up to SOLCLIENT_SESSION_PROP_BUFFER_SIZE bytes on transmit. This buffering is dynamic and does not consume memory when not in use.

Supported Topic Syntax

Topics are NULL-terminated UTF-8 strings in the form "level1/level2/level3". The total length of a Topic can be 250 bytes, not including the NULL terminator.

Supported Subscription Syntax

Subscriptions are in the form "level1/level2/level3".
The total length of a subscription can be 250 bytes.
The '>' character, when alone at the final level of a subscription, means match one or more levels at the end of a received topic. For example, "level1/level2/level3/>" matches "level1/level2/level3/level4" and "level1/level2/level3/level4/level5", but not "level1/level2/level3".
'>' elsewhere in the subscription has no special meaning. For example, "level1>/level2".
The '*' character is a wildcard. When alone at a level, it means match any string at that level in a received topic. For example, "level1/ * /level3" matches "/level1/level2/level3".
'*' can also be used to match a level that starts with a specified string.
For example "level1/lev* /level3" matches "/level1/level2/level3".
A '*'cannot appear at the beginning or within a string. For example, "lev*1" and "*evel" are not valid.

Dispatching Messages Based on a Topic

By default, when subscriptions are added, all messages are dispatched to the Session message receive callback that is defined when the Session is created (through the solClient_session_createFuncInfo_t parameter of solClient_session_create). However, a Session can also be configured through the Session property SOLCLIENT_SESSION_PROP_TOPIC_DISPATCH to dispatch messages with specific Topic destinations to a message receive callback that is specified when a Topic subscription is added ( solClient_session_topicSubscribeWithDispatch()). Dispatching/demultiplexing incoming messages based on the Topic associated with the message allows different callbacks to be invoked based on the received topic. It also allows different application data to be provided to the callback based on the matching subscription. Full wildcard subscription syntax is supported (refer to Supported Subscription Syntax).

As an example, consider the following Topic dispatch descriptions:
solClient_session_rxMsgDispatchFuncInfo_t dispatch1 = {SOLCLIENT_DISPATCH_TYPE_CALLBACK, msgCallback1Func, &item1Data, NULL };
solClient_session_rxMsgDispatchFuncInfo_t dispatch2 = {SOLCLIENT_DISPATCH_TYPE_CALLBACK, msgCallback1Func, &item2Data, NULL };
solClient_session_topicSubscribeWithDispatch( session_p, 0, "level1/item1", &dispatch1, NULL );
solClient_session_topicSubscribeWithDispatch( session_p, 0, "level1/item2", &dispatch2, NULL);
When a message is received with Topic "level1/item1", msgCallback1Func is called with a pointer to the application's item1Data structure. When a message is received with Topic "level1/item2", msgCallback1Func is called with a pointer to the application's item2Data structure. A Topic dispatch subscription is uniquely identified by the tuple <subscription, callback_p, user_p, NULL (reserved for future use)>, any number of message callback functions can be used.

When Topic dispatching is enabled, the Session callback is still used for subscriptions that are created through solClient_session_topicSubscribe() or solClient_session_topicSubscribeExt, but only if no other callback has been invoked for a received message. So the Session callback acts as a "default" callback. For example, consider what occurs when the following subscription is added to the preceding example:
solClient_session_topicSubscribeExt( session_p, 0, "level1/>");

The application subscribes to all topics under level1, but "level1/item1" and "level1/item2" go to the msgCallback1Func callback with the specified user_p, while any other Topic starting with "level1/" go to the default Session message callback. This allows an application to trap certain topics to a specified callback and send others to the Session callback.

If a message matches subscriptions that use the Topic dispatch Session callback, then each matching subscription invokes a callback, and the application can receive and process a message multiple times. For example:
solClient_session_rxMsgDispatchFuncInfo_t dispatchA = {SOLCLIENT_DISPATCH_TYPE_CALLBACK, msgCallbackAFunc, &userDataA, NULL };
solClient_session_rxMsgDispatchFuncInfo_t dispatchB = {SOLCLIENT_DISPATCH_TYPE_CALLBACK, msgCallbackBFunc, &userDataB, NULL };
solClient_session_rxMsgDispatchFuncInfo_t dispatchC = {SOLCLIENT_DISPATCH_TYPE_CALLBACK, msgCallbackCFunc, &userDataC, NULL };
solClient_session_topicSubscribeWithDispatch( session_p, 0, "part1/item1", &dispatchA, NULL);
solClient_session_topicSubscribeWithDispatch( session_p, 0, "part1/item1", &dispatchB, NULL);
solClient_session_topicSubscribeWithDispatch( session_p, 0, "part1/>", &dispatchC, NULL);
In this example, when a message arrives with Topic "part1/item1", it is delivered to each of the msgCallbackAFunc, msgCallbackBFunc, and msgCallbackCFunc callback functions. When a message arrives with the Topic "part1/item2", it is only delivered to the msgCallbackCFunc callback function. Note that when a message does not match a specific callback and is being delivered to the default Session message received callback, it is only delivered once to that callback, independent of the number of subscriptions it matched.

Each unique Topic subscription is also added to the Solace messaging broker and removed when there are no longer any dispatch functions associated with the subscription. Applications that want to have fine-grained control over broker resources may choose to add dispatch Session callback functions only without adding a subscription to the broker. When the subscription flag SOLCLIENT_SUBSCRIBE_FLAGS_LOCAL_DISPATCH_ONLY is set, the subscription is not added to the broker. For example:
solClient_session_rxMsgDispatchFuncInfo_t dispatchA = {SOLCLIENT_DISPATCH_TYPE_CALLBACK, msgCallbackAFunc, &userDataA, NULL };
solClient_session_rxMsgDispatchFuncInfo_t dispatchB = {SOLCLIENT_DISPATCH_TYPE_CALLBACK, msgCallbackBFunc, &userDataB, NULL };
solClient_session_rxMsgDispatchFuncInfo_t dispatchC = {SOLCLIENT_DISPATCH_TYPE_CALLBACK, msgCallbackCFunc, &userDataC, NULL };
solClient_session_topicSubscribeWithDispatch( session_p, SOLCLIENT_SUBSCRIBE_FLAGS_LOCAL_DISPATCH_ONLY, "part1/item1", &dispatchA, NULL);
solClient_session_topicSubscribeWithDispatch( session_p, SOLCLIENT_SUBSCRIBE_FLAGS_LOCAL_DISPATCH_ONLY, "part1/item2", &dispatchB, NULL);
solClient_session_topicSubscribeWithDispatch( session_p, 0, "part1/>", &dispatchC, NULL);
In this example, the application avoids adding the subscriptions for "part1/item1" and "part1/item2" to the broker as these subscriptions overlap with the wildcard subscription "part1/>". All messages are forwarded to the application due to the last wildcard subscription, and properly dispatched by the more specific non-wildcard subscriptions.

When unsubscribing, a specified callback can be removed through solClient_session_topicUnsubscribeWithDispatch(). For example:
solClient_session_rxMsgDispatchFuncInfo_t removedispatchA = {SOLCLIENT_DISPATCH_TYPE_CALLBACK, msgCallbackAFunc, &userDataA, NULL };
solClient_session_topicUnsubscribeWithDispatch( session_p, 0, "part1/item1", &removedispatchA, NULL);

Note: When unsubscribing the pointer to the dispatch information (&removedispatchA) does not have to exactly match the pointer used to create the Topic dispatch entry, but the contents must describe the entry to be removed.

The interface solClient_session_topicUnsubscribe() or solClient_session_topicUnsubscribeExt() can only be used to remove subscriptions for the default Session callback. When calling solClient_session_topicUnsubscribeWithDispatch(), providing a NULL pointer for the callback and the user pointer or providing a NULL pointer to the dispatch information is equivalent to calling solClient_session_topicUnsubscribeExt().

Dispatching Messages Based on a Topic for a Flow

Topic dispatching is also available on Flows to Queues and Topic Endpoints.

A Queue endpoint Flow may have many topics associated with it. Topics may be added to Queue endpoint Flows with the Session function, solClient_session_endpointTopicSubscribe(), or with the Flow function, solClient_flow_topicSubscribeWithDispatch().

A Topic Endpoint Flow only has a single Topic which is defined when the Flow is created (see SOLCLIENT_FLOW_PROP_TOPIC). Topic dispatching for a Topic Endpoint Flow can be useful when the Flow's Topic contains wildcards because the Topic dispatching capability can then be used to separate out different topics covered by the Flow's wildcard topic.

As with solClient_session_topicSubscribeWithDispatch(), the subscribe flag SOLCLIENT_SUBSCRIBE_FLAGS_LOCAL_DISPATCH_ONLY may be used on a Queue endpoint Flow to add a dispatch callback entry only. SOLCLIENT_SUBSCRIBE_FLAGS_LOCAL_DISPATCH_ONLY is implied on a Topic Endpoint Flow as adding topics dynamically to a Topic Endpoint is not supported.

solClient_flow_topicSubscribeWithDispatch() can be used to add a Topic subscription only (no dispatch entry) to the Queue endpoint by setting the dispatch information to NULL.

Similar to a Session, Topic dispatching on a Flow is controlled by the functions solClient_flow_topicSubscribeWithDispatch() and solClient_flow_topicUnsubscribeWithDispatch(). Note that for a Topic Endpoint the solClient_flow_topicSubscribeWithDispatch() and solClient_flow_topicUnsubscribeWithDispatch() functions only control the dispatching of messages received on the Flow and do not affect which messages are received on the Flow. The only property that controls the messages received on a Flow to a Topic Endpoint is SOLCLIENT_FLOW_PROP_TOPIC.

No check is made to ensure that any Topic subscribed to through solClient_flow_topicSubscribeWithDispatch() is actually received on the Topic Endpoint Flow. For example, if the Topic Endpoint Flow was created with Topic 'level1/>', if solClient_flow_topicSubscribeWithDispatch() is invoked with a Topic of 'level2/level3', that topic is accepted, but the callback for that Topic is never invoked as the Flow will not attract messages that match that topic.

Configuring Host Entry for SOLCLIENT_SESSION_PROP_HOST property

The entry for the SOLCLIENT_SESSION_PROP_HOST property should provide a protocol, host, and port. The SOLCLIENT_SESSION_PROP_HOST property may also include an optional Proxy Server configuration, separated from the message router configuration by a percent (%) sign.

  • [Protocol:]Host[:Port][%ProxyService] or [Protocol://]Host[:Port][%ProxyService]

Protocol is the protocol used for the transport channel. The valid values are:

  • tcp - use a TCP channel for communications between the application and its peers. If no protocol is set, tcp is used as a default.
  • tcps - use a SSL channel over TCP for communications between the application and its peers.
  • http - use HTTP channels or a WebSocket channel over TCP for communications between the application and its peers. Web Messaging with compression is not supported.
  • https - use HTTP channels or a WebSocket channel over SSL for communications between the application and its peers. Web Messaging with compression is not supported.

Host is the IPv4 or IPv6 address or host name to connect to for a connection. IPv6 addresses must be enclosed in brackets ([]).

Port is the port to connect to for a connection. A value is only required when using a port other than the automatically assigned default port number. The default port for TCP is 55555 when compression is not in use, or 55003 when compression is in use. The default port for SSL is 55443. The default port for HTTP or WebSocket over TCP is 80. The default port for HTTP or WebSocket over SSL is 443.

ProxyService is a description of the non-transparent proxy. If it is necessary to configure the proxy server that is used to connect to the message router, then the proxy server is configured in the ProxyService string. The ProxyService string format is specified as:

  • [ProxyProtocol]://[username:password@]proxyHost[:proxyPort]

ProxyProtocol is the protocol used to communication with the proxy server. The valid values are:

  • socks5 - Connect to the server with the SOCKS Protocol Version 5, RFC 1928 (IETF Standards Track Document)
  • httpc - Connect to the server with the HTTP Connect Protocol, RFC 2817 (IETF Standards Track Document)

If authentication is required for the proxy server, the username and password may be optionally specified before the proxy host.

proxyHost is the IPv4 or IPv6 address or host name of the proxy server.

proxyPort is the port to connect to for a connection. If the port number is not specified, the default for SOCKS5 is port 1080, and the default for Http-Connect is port 3128.

The following examples show how to specify transport channel types. Unless it is otherwise specified, the default port 55555 is used.

  • 192.168.160.28 - connect to IP address 192.168.160.28 and the default port 55555 over TCP.
  • [fe80::1] - connect to IPV6 address fe80::1 and the default port 55555 over TCP.
  • tcp:192.168.160.28 - connect to IP address 192.168.160.28 and the default port 55555 over TCP.
  • tcps:192.168.160.28 - connect to IP address 192.168.160.28 and the default port 55443 over SSL over TCP.
  • tcps:[fe80::1] - connect to IPV6 address fe80::1 and the default port 55443 over SSL over TCP.
  • tcp:192.168.160.28:44444 - connect to IP address 192.168.160.28 and port 44444 over TCP.
  • tcp:[fe80::1]:44444 - connect to IPV6 address fe80::1 and port 44444 over TCP.
  • http ://192.168.160.28 - connect to IP address 192.168.160.28 and the default port 80 over HTTP or WebSocket over TCP.
  • https ://192.168.160.28 - connect to IP address 192.168.160.28 and the default port 443 over HTTP or WebSocket over SSL over TCP.

The following examples show how to connect to a message router through a proxy server.

  • 192.168.160.28%socks5://192.168.1.1 - connect to message router at 192.168.160.28 through a SOCKS5 proxy server at 192.168.1.1.
  • 192.168.160.28%httpc://192.168.1.1 - connect to message router at 192.168.160.28 through a HTTP-Connect proxy server at 192.168.1.1.
  • tcps:solace.company.com%socks5://User:PassWord@proxy.company.com:13128 - connect to message router at solace.company.com using SSL over TCP through a SOCKS5 proxy server at proxy.company.com, port 13128. Authenticate with the proxy server using username User and password PassWord.
  • http ://192.168.160.27:44444%httpc://proxy.company.com:11080 - connect to the message router at 192.168.160.28, port 44444, using HTTP. Connect through the proxy server at proxy.company.com, port 11080.
  • [fe80::1]%socks5://[fe80::2] - connect message router at [fe80::1] through a SOCKS5 proxy server at [fe80::2].

The SOLCLIENT_SESSION_PROP_HOST property also supports multiple host entries separated by comma.

Configuring Multiple Hosts for Redundancy and Failover

You can provide up to sixteen potential hosts for a client application to connect or reconnect to. Typically the listed brokers are in separate geographic locations, and the use of a host list allows your client applications to fail over to the alternate connections should the first broker be unavailable. The host list is configured in the SOLCLIENT_SESSION_PROP_HOST property as a comma-separated list of hosts. Each host may optionally include a port number as well. For example, if there are two brokers at 192.168.160.128 and 192.168.160.129, but the second is using the non-default port 50005 for the message bus, the SOLCLIENT_SESSION_PROP_HOST would be configured as:
"192.168.160.128,192.168.160.129:50005".

If a client application publishes Guaranteed messages (send flags of SOLCLIENT_DELIVERY_MODE_PERSISTENT or SOLCLIENT_DELIVERY_MODE_NONPERSISTENT) in a Session, and then a disconnect occurs, the API will automatically reconnect to other listed hosts. However, because another host will not know the state of the publisher flow to the original host, the API must reset publisher flow state. Unacknowledged messages are renumbered and resent by the API. If the alternate router is configured as a replication site this may lead to duplicate messages in the system. It is up to the application to resolve this duplication in what ever way is appropriate to the application.

Applications may wish to configure the session so that auto-reconnect only occurs if no guaranteed messages have been published. This is the legacy behaviour of the API. If this is desired then set the session property SOLCLIENT_SESSION_PROP_GD_RECONNECT_FAIL_ACTION to the value SOLCLIENT_SESSION_PROP_GD_RECONNECT_FAIL_ACTION_DISCONNECT. This session property can also be set as environment variable which then allows legacy applications to run without modification or recompile.

In the given example, with the SOLCLIENT_SESSION_PROP_HOST configured as:
"192.168.160.128,192.168.160.129:50005"
when solClient_session_connect() is called, SolClient will attempt to connect, first to 192.168.160.128. If that connection fails for any reason, it will attempt to connect to 192.168.160.129:50005. This process is repeated until all entries in the host list are attempted. After each entry has been attempted, and if all fail, the Session properties SOLCLIENT_SESSION_PROP_CONNECT_RETRIES and SOLCLIENT_SESSION_PROP_RECONNECT_RETRY_WAIT_MS determine the behavior of SolClient. If SOLCLIENT_SESSION_PROP_CONNECT_RETRIES is non-zero, SolClient waits for up to the number of milliseconds set for SOLCLIENT_SESSION_PROP_RECONNECT_RETRY_WAIT_MS then starts a connection attempt again from the beginning of the list.

If an established Session fails, to any host in the list, when SOLCLIENT_SESSION_PROP_RECONNECT_RETRIES is non-zero, then SolClient automatically attempts to reconnect, starting at the beginning of the list.

The Session connect timer, SOLCLIENT_SESSION_PROP_CONNECT_TIMEOUT_MS, runs separately for each connection attempt. So an application waiting for a connection established (SOLCLIENT_SESSION_EVENT_UP_NOTICE) or connection failure (SOLCLIENT_SESSION_EVENT_CONNECT_FAILED_ERROR) may have to wait up to (<number of hosts in list> times SOLCLIENT_SESSION_PROP_CONNECT_TIMEOUT_MS) for the event.

Feature Limitations

File descriptor limits in non-Linux operating systems restrict the number of files that can be managed per process to 1024. These limitations are due to the use of select(2) to poll devices so the Messaging API for C may not manage any single file descriptor which has a numerical value that exceeds 1024.

If the C API is used in an application that connects to a Solace messaging broker, channel connect failures can occur if there are more than 1024 Sessions created per process. This limit is further reduced by any other files not managed by the C API that the application has open.

Similarly, on Windows platforms, a single Context (see solClient_context_create()) cannot manage more than 64 Sessions. Exceeding these limits can cause calls to solClient_session_create() to fail. An application that registers its own file descriptor handlers (by providing non-null function pointers in solClient_context_createRegisterFdFuncInfo_t) is not limited in the Messaging API for C, but the application might have its own limitations.

In all non-Linux and non-Windows systems, an application that provides its file descriptors to the C API to manage (by calling solClient_context_registerForFdEvents()), may not provide a file decsriptor with a numerical value greater than or equal to 1024.

OpenSSL Certificate Validation

Note on certificate validation:

When validating certificates, the messaging APIs for C and .NET use the following validation rules, after building the chain from the server certificate to a self-signed root certificate using certificates presented by the server and certificates in the trust store :

  • Verify the root certificate is trusted.
  • Verify depth of the chain is <= 3.

Java and JMS messaging APIs use the same rules as C and .NET with the following exceptions:

  • Depth validation is not enforced in Java or JMS.
  • When the server presents an incomplete certificate chain, Java/JMS messaging APIs only require the signer of the incomplete certificate chain to be in the trust store, where this could be insufficient for C/.NET APIs.

Therefore C and .NET messaging APIs certificate validation rules are more restrictive, hence if a certificate is accepted by C or .NET, it will definitely be accepted by Java and JMS.

Transacted Session

Client applications can create one or more transacted sessions within a non-transacted session. The lifecycle of a transacted session is bounded by the lifecycle of its non-transacted parent session. In other words, when a session is destroyed/disposed, all transacted sessions created within this session will be destroyed/disposed too. A transacted session can have at most one publisher flow and zero or many subscriber flows. All messages sent/received by a transacted session must have a guaranteed delivery mode, there is no support for direct transport messages.

Message Dispatcher:

Asynchronous message delivery to client applications within a Transacted Session (i.e. message consumers created from Transacted Sessions) cannot happen over the context thread. Therefore, asynchronous message delivery within a Transacted Session will be done within an implicitly created Message Dispatcher.
There are two types of Message Dispatchers, which client applications can choose when a Transacted Session is created.

  • Context-bound: A Message Dispatcher lazily created by the Context. A Context can have at most one context-bound Message Dispatcher.
  • TransactedSession-bound: A Message Dispatcher lazily created by a Transacted Session.

The lifecycle of a message dispatcher is bounded to the lifecycle of the corresponding API object. There are advantages and disadvantages when using TransactedSession-bound message dispatchers.

  • The main advantage is improved responsiveness. It is also possible to improve application performance, especially with multi-core processors.
  • The main disadvantage is that programing and debugging is more complex as applications must be more multi-thread aware. In environments where there is contention for CPU resources, there is more overhead managing and switching between threads.

Receiving Messages:

The main differences between receiving messages from a transacted consumer Flow and from a non-transacted Flow are:

  • For a transacted consumer Flows (created by a Transacted Session), function solClient_flow_sendAck() returns OK and no operation (NOP) is performed.
  • If a Rx message callback is provided when a transacted consumer Flow is created, messages received on the flow are dispatched to the callbacks with the usual user_p just as on non-transacted Flows, but in the context of an internal Contex-bound or TransactedSession-bound Message Dispatcher thread.
  • For transacted Flows created without Rx message callbacks, messages received on Flows are queued internally. Applications must call function solClient_flow_receiveMsg directly to retrieve messages from those internal queues.

Publishing Messages:

To publish guaranteed messages on a Transacted Session, Transacted Session property SOLCLIENT_TRANSACTEDSESSION_PROP_HAS_PUBLISHER must be enabled when the Transacted Session is created.

The main differences between publishing guaranteed messages from a Transacted Session and from a Session are:

  • For a Transacted Session, a successful commit acknowledges published messages.
  • For a Transacted Session, ACKs and NACKs from the broker are ignored.

Multithreading:

Transacted Sessions are not thread-safe and a single Transacted Session should not be accessed by multiple application threads. The legal use cases for a transacted session, which are not enforced by the API, are limited to:

  • If messages are received by Rx message callbacks, invoke commit/rollback/sendMsg only from receiving message callbacks (i.e. in the context of an internal Message Dispatcher thread).
  • If messages are received from an application thread by calling solClient_flow_receiveMsg() directly, commit/rollback/sendMsg/receiveMsg functions must be called in the context of the same application thread.