API Threading

The APIs use a Context to organize communications between a client application and a Solace PubSub+ event broker. A Context acts as a container for configuring one or more Sessions and handling Session-related events, and it encapsulates threads that drive network I/O and message delivery notification for the Sessions. Message delivery and reception can also require application-provided threads.

Threading When Publishing Messages

The client application provides the processing thread required to publish Guaranteed messages to a destination on the event broker.

When the event broker successfully receives Guaranteed messages, it returns acknowledgments to the API. It does not return acknowledgments for Direct messages. (The exception to this is publishing Direct messages using JCSMP's non-streaming publishing mode.)

The Context uses a processing thread to read the acknowledgment from the event broker. It then parses the windowed acknowledgment, enqueues separate acknowledgments for each message (identified by a message ID), then dispatches them to an application callback.

JCSMP

When publishing messages using the streaming publishing mode, a Context uses one thread to read the windowed acknowledgment that the event broker sends for a group of consecutive Guaranteed messages, parse it and then enqueue separate acknowledgments on the producer notification dispatcher queue for each message. This queue is also used for message publishing exceptions. There is one queue for each Context.

The Context uses another thread for notification and dispatching the queued acknowledgments to an application callback.

Note that if there is not enough space on the queue when the thread attempts to append notifications to it, the thread can block until there is sufficient space. The queue size can be modified through JCSMPGlobalProperties.setProducerDispatcherQueueSize().

The figure below shows the application thread used to send Guaranteed messages and the Context threads that are used handle a windowed message acknowledgment from the event broker.

Publishing Guaranteed Messages Through JCSMP Using Streaming Mode

Java RTO, C, and .NET APIs

In the Java RTO, C, and .NET APIs, a Context uses a single thread to read the windowed acknowledgment that the event broker sends for the received Guaranteed messages and parse them. Unlike JCSMP, acknowledgments from the event broker are not placed in a notification queue; rather, the same thread is used for notification and dispatching the queued acknowledgments to an application callback.

The figure below shows the application thread used to send Guaranteed messages and the Context thread used to handle windowed message acknowledgments from the event broker.

Publishing Guaranteed Messages Using the C and .NET APIs

JavaScript and Node.js APIs

The JavaScript and Node.js APIs are single-threaded including notification and dispatching the acknowledgments to application event listeners.

Threading When Receiving Messages

When receiving published messages, the Context uses a processing thread to read messages off the socket, parse them, and then, depending on the messaging API and whether a synchronous or asynchronous mode is used, enqueue the messages for delivery or consumption, or perform customer notification and message dispatch.

Client applications can use one of the following modes to receive published messages:

Receiving Messages Asynchronously

A client application can use JCSMP, Java RTO, C, and .NET APIs to receive messages in an asynchronous manner. That is, when messages are available, they are automatically sent (“pushed”) to a message callback or message delegate interface from the API to the client application.

When receiving messages asynchronously, the Context uses a processing thread for consumer notification and dispatching the queued messages to consumers; all callbacks from the API to the application, such as message receive callbacks, event callbacks, and timer callbacks, run from a Context thread.

When a client application is using asynchronous transacted sessions, messages are dispatched from one or more transacted session dispatcher threads. Either a single transacted session dispatcher thread that is bound to the Context (this is the default) or separate transacted session dispatcher threads that are bound to each transacted session can be used. For more information, refer to Using Local Transactions.

JCSMP

By default, the JCSMP’s Context uses one thread to read messages off the socket, parse them, and then enqueue them on the consumer notification dispatcher queue. It uses another thread for consumer notification and dispatching the queued messages to consuming client applications.

The maximum number of messages that can be queued by the Context per Session before they are delivered to consumers is as follows:

  • Direct messages—5,000
  • Guaranteed messages—The maximum number of messages permitted by each flow’s Guaranteed message window size. (A Guaranteed message window size limits the number of messages that the API can receive before it must return an acknowledgment to the event broker that it received the messages in the window.)

The consumer notification dispatcher queue that is used to asynchronously notify consumers of messages and exceptions through an XMLMessageListener can be resized, if necessary. This queue should be large enough to buffer the maximum number of notifications that are generated for all consumer flows (Guaranteed and Direct messages) in all of the Sessions in a Context. If an XMLMessageListener does not always return control quickly and the consumer notification dispatcher queue fills up, the API thread attempting to enqueue notifications to this queue can be temporarily blocked and can cause messages to queue on the event broker.

To resize the consumer notification dispatcher queue, call JCSMPGlobalProperties.setConsumerDispatcherQueueSize().

Global properties may only be set before any Sessions have been created from the JCSMPFactory.

The figure below shows the Context threads that are used to receive messages asynchronously through JCSMP.

Receiving Messages Asynchronously Using JCSMP

For ultra low latency applications, you can enable the MESSAGE_CALLBACK_ON_
REACTOR
Session property to reduce message latency. When this Session property is enabled, messages delivered asynchronously to an XMLMessageListener are delivered directly from the I/O thread instead of from the consumer notification and dispatch thread. Although enabling this Session property reduces message latency, it also decreases the maximum message throughput.

An application using the MESSAGE_CALLBACK_ON_REACTOR Session property must not call any blocking methods in the onReceive() callback; doing so could cause the application to deadlock.

The figure below shows the Context thread that is used to receive messages asynchronously through JCSMP when the MESSAGE_CALLBACK_ON_REACTOR Session property is enabled.

Receiving Messages Asynchronously Through JCSMP when the Message Callback on Reactor is Enabled

Java RTO, C, and .NET APIs

Contexts used by the Java RTO, C, and .NET APIs asynchronously receive messages in a way similar to that used by JCSMP when the MESSAGE_CALLBACK_ON_REACTOR Session property is enabled. The Java RTO, C, and .NET APIs only use one processing thread for the Context. This thread reads messages off the socket, parses them, and then performs consumer notification and dispatches the messages to consuming applications.

For the C API, the required Context thread can optionally be supplied by the client application instead of relying on the internal API thread. Refer to C API Best Practices.

Receiving Messages Asynchronously With Java RTO, C, and .NET APIs

JavaScript and Node.js APIs

The JavaScript and Node.js APIs are single-threaded including asynchronous receiving of messages through application message event listeners.

Receiving Messages Synchronously

When receiving messages in a synchronous manner, the client application uses explicit receive calls to retrieve messages from the message queues that the API uses for each consumer. When receiving messages synchronously, the client application provides the threads that “pull” the enqueued messages from the API.

JCSMP

To receive messages, the client application must use start() to enable receiving messages from the event broker, and then use synchronous receive(...) calls to receive the next available message. The receive methods can manage the potential blocks by waiting indefinitely until there are messages, not waiting when there are no messages (that is, immediately timing out when there are no messages), or timing out after a set period of time when there are no messages.

The figure below shows the Context thread and application threads that are used when messages are received synchronously through JCSMP.

Receiving Messages Synchronously Using the JCSMP

Illustration depicting the concepts described in the surrounding text.

Java RTO, C, and .NET APIs

The Java RTO, C, and .NET APIs can only receive messages asynchronously in a non-transacted Session. However, these APIs can receive messages synchronously within a Transacted Session.

JavaScript and Node.js APIs

Receiving messages synchronously is not supported for the JavaScript and Node.js APIs.