Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Generally speaking, when an error occurs that prohibits an operation from succeeding, AMPS will throw an exception. AMPS exceptions universally derive from AMPS.AMPSException
, so by catching AMPSException
, you will be sure to catch anything AMPS throws, for example:
In this example, if an error occurs, the program writes the error to stderr
and the publish()
command fails. However, client
is still usable for continued publishing and subscribing. When the error occurs, the exception is written to the console. As with most Python exceptions, str()
will convert the exception into a string that includes a descriptive message.
AMPS exception types vary based on the nature of the error that occurs. In your program, if you would like to handle certain kinds of errors differently than others, you can handle the appropriate subclass of AMPSException
to detect those specific errors and do something different.
Every distributed system will experience occasional disconnections between one or more nodes. The reliability of the overall system depends on an application's ability to efficiently detect and recover from these disconnections. Using the AMPS Python client's disconnect handling, you can build powerful applications that are resilient in the face of connection failures and spurious disconnects. For additional reliability, you can also use the high availability client (discussed in the following sections), which provides both disconnect handling and features to help ensure that messages are reliably delivered.
The named convenience methods and the Command
class provide a timeout
setting that specifies how long the command should wait to receive a processed
acknowledgment from AMPS. This can be helpful in cases where it is important for the caller to limit the amount of time to block waiting for AMPS to acknowledge the command. If the AMPS client does not receive the processed acknowledgment within the specified time, the client sends an unsubscribe
command to the server to cancel the command and throws an exception.
Acknowledgments from AMPS are processed by the client receive thread on the same socket as data from AMPS. This means that any other data previously returned (such as the results of a large query) must be consumed before the acknowledgment can be processed. An application that submits a set of SOW queries in rapid succession should set a timeout that takes into account the amount of time required to process the results of the previous query.
When using asynchronous message processing, exceptions thrown from the message handler are silently absorbed by the AMPS Python client by default. The AMPS Python client allows you to register an exception listener to detect and respond to these exceptions. When an exception listener is registered, AMPS will call the exception listener with the exception.
See for details.
In every distributed system, the robustness of your application depends on its ability to recover gracefully from unexpected events. The AMPS client provides the building blocks necessary to ensure your application can recover from the kinds of errors and special events that may occur when using AMPS.
The HAClient
class, included with the AMPS Python client, contains a disconnect handler and other features for building highly-available applications. The HAClient
includes features for managing a list of failover servers, resuming subscriptions, republishing in-flight messages, and other functionality that is commonly needed for high availability. 60East recommends using the HAClient
for automatic reconnection wherever possible, as the HAClient disconnect handler has been carefully crafted to handle a wide variety of edge cases and potential failures.
If an application needs to reconnect or fail over, use an HAClient
, and the AMPS client library will automatically handle failover and reconnection. You control which servers the client fails over to using an implementation of the ServerChooser
interface, and you can control the timing of the failover using an implementation of the ReconnectDelayStrategy
interface.
For most applications, the combination of the HAClient
disconnect handler and a ConnectionStateListener
gives you the ability to monitor disconnections and add custom behavior at the appropriate point in the reconnection process.
If you need to add custom behavior to the failover (such as logging, resetting an internal cache, refreshing credentials and so on), the ConnectionStateListener
class allows your application to be notified and take action when disconnection is detected and at each stage of the reconnection process.
To extend the behavior of the AMPS client during reconnection, implement a ConnectionStateListener
as described in the section on Monitoring Connection State.
The AMPS client includes a heartbeat feature to help applications detect disconnection from the server within a predictable amount of time. Without using a heartbeat, an application must rely on the operating system to notify the application when a disconnect occurs. For applications that are simply receiving messages, it can be impossible to tell whether a socket is disconnected or whether there are simply no incoming messages for the client.
When you set a heartbeat, the AMPS client sends a heartbeat message to the AMPS server at a regular interval, and waits a specified amount of time for the response. If the operating system reports an error on send, or if there is no activity received from the server within the specified amount of time, the AMPS client considers the server to be disconnected. Likewise, the server will ensure that traffic is sent to the client at the specified interval, using heartbeat messages when no other traffic is being sent to the client. If, after sending a heartbeat message, no traffic from the client arrives within a period twice the specified interval, the server will consider the client to be disconnected or nonresponsive.
The AMPS client processes heartbeat messages on the client receive thread, which is the thread used for asynchronous message processing. If your application uses asynchronous message processing and occupies the thread for longer than the heartbeat interval, the client may fail to respond to heartbeat messages in a timely manner and may be disconnected by the server.
The following table details each of the exception types thrown by AMPS.
Exception
When
Notes
AlreadyConnectedException
Connecting
Thrown when connect()
is called on a Client
that is already connected.
AMPSException
Anytime
Base class for all AMPS exceptions.
AuthenticationException
Anytime
Indicates an authentication failure occurred on the server.
BadFilterException
Subscribing
This typically indicates a syntax error in a filter expression.
BadRegexTopicException
Subscribing
Indicates a malformed regular expression was found in the topic name.
CommandException
Anytime
Base class for all exceptions relating to commands sent to AMPS.
ConnectionException
Anytime
Base class for all exceptions relating to the state of the AMPS connection.
ConnectionRefusedException
Connecting
The connection was actively refused by the server. Validate that the server is running, that network connectivity is available, and the settings on the client match those on the server.
DisconnectedException
Anytime
No connection is available when AMPS needed to send data to the server or the user's disconnect handler threw an exception.
InvalidTopicException
SOW query
The topic is not configured for the requested operation. For example, a sow
command was issued for a topic that is not in the SOW or a bookmark subscribe was issued for a topic that is not recorded in the transaction log.
InvalidTransportOptionsEx
ception
Connecting
An invalid option or option value was specified in the URI.
InvalidUriException
Connecting
The URI string provided to connect()
was formatted improperly.
MessageTypeException
Connecting
The class for a given transport's message type was not found in AMPS.
NameInUseException
Connecting
The client name (specified when instantiating Client
) is already in use on the server.
RetryOperationException
Anytime
An error occurred that caused processing of the last command to be aborted. Try issuing the command again.
StreamException
Anytime
Indicates that data corruption has occurred on the connection between the client and server. This usually indicates an internal error inside of AMPS -- contact AMPS support.
SubscriptionAlreadyExists
Exception
Subscribing
A subscription has been requested using the same command ID string as another subscription. Create a unique command ID string for every subscription.
TimedOutException
Anytime
A timeout occurred waiting for a response to a command.
TransportTypeException
Connecting
Thrown when a transport type is selected in the URI that is unknown to AMPS.
UnknownException
Anytime
Thrown when an internal error occurs. Contact AMPS support immediately.
UsageException
Changing the properties of an object
Thrown when the object is not in a valid state for setting the properties. For example, some properties of a Client
(such as the name) cannot be changed while that client is connected to AMPS.
The AMPS Python client handles most incoming messages and takes appropriate action. Some messages are unexpected or occur only in very rare circumstances. The AMPS Python client provides a way for clients to process these messages. Rather than providing handlers for all of these unusual events, AMPS provides a single handler function for messages that can't be handled during normal processing.
Your application registers this handler by setting the last_chance_message_handler
for the client. This handler is called when the client receives a message that can't be processed by any other handler. This is a rare event, and typically indicates an unexpected condition.
For example, if a client publishes a message that AMPS cannot parse, AMPS returns a failure acknowledgment. This is an unexpected event, so AMPS does not include an explicit handler for this event, and failure acknowledgments are received in the method registered as the last_chance_message_handler
.
Your application is responsible for taking any corrective action needed. For example, if a message publication fails, your application can decide to republish the message, publish a compensating message, log the error, stop publication altogether, or any other action that is appropriate.
The publish
methods in the Python client deliver the message to be published to AMPS then return immediately, without waiting for AMPS to return an acknowledgment. Likewise, the sow_delete
methods request deletion of SOW messages, and return before AMPS processes the message and performs the deletion. This approach provides high performance for operations that are unlikely to fail in production. However, this means that the methods return before AMPS has processed the command, without the ability to return an error in the event the command fails.
The AMPS Python client provides a failed_write_handler
that is called when the client receives an acknowledgment that indicates a failure to persist data within AMPS. As with the last_chance_message_handler
described in the {ref}Unexpected Messages <#unexpected-messages>
section, your application registers a handler for this function. When an acknowledgment returns that indicates a failed write, AMPS calls the registered handler method with information from the acknowledgment message, supplemented with information from the client publish store if one is available. Your client can log this information, present an error to the user or take whatever action is appropriate for the failure.
If your application needs to know whether publishes succeeded and are durably persisted, the following approach is recommended:
Set a PublishStore
on the client. This will ensure that messages are retransmitted if the client becomes disconnected before the message is acknowledged and request persisted
acknowledgments for messages.
Install a failed_write_handler
. In the event that AMPS reports an error for a given message, that event will be reported to the failed_write_handler
.
Call publish_flush()
and verify that all messages are persisted before the application exits.
When no failed_write_handler
is registered, acknowledgments that indicate errors in persisting data are treated as unexpected messages and routed to the last_chance_message_handler
. In this case, AMPS provides only the acknowledgment message and does not provide the additional information from the client publish store.
In some cases, an application does not want the AMPS client to reconnect, but instead wants to take a different action if disconnection occurs. For example, a stateless publisher that sends ephemeral data (such as telemetry or prices) may want to exit with an error if the connection is lost rather than risk falling behind and providing outdated messages. Often, in this case, a monitoring process will start another publisher if a publisher fails, and it is better for a message to be lost than to arrive late.
To cover cases where the application has unusual needs, the AMPS client library allows an application to provide custom disconnect handling.
Your application gets to specify exactly what happens when a disconnect occurs by supplying a function to client.set_disconnect_handler()
, which is invoked whenever a disconnect occurs. This may be helpful for situations where a particular connection needs to do something completely different than reconnecting or failing over to another AMPS server.
Setting the disconnect handler completely replaces the disconnection and failover behavior for an HAClient
and provides the only disconnection and failover behavior for a Client
.
The handler runs on the thread that detects the disconnect. This may be the client receive thread (for example, if the disconnect is detected due to heartbeating) or an application thread (for example, if the disconnect is detected when sending a command to AMPS).
The example below shows the basics:
When using the asynchronous interface, exceptions can occur that are not thrown to the user. For example, when an exception occurs in the process of reading subscription data from the AMPS server, the exception occurs on a thread inside of the AMPS Python client. Consider the following example using the asynchronous interface:
In this example, we set up a subscription to wait for messages on the pokes topic, whose Pokee tag begins with our user name. When messages arrive, we print a message out to the console, but otherwise our application waits for a key to be pressed.
Inside of the AMPS client, the client creates a new thread of execution that reads data from the server, and invokes message handlers and disconnect handlers when those events occur. When exceptions occur inside this thread, however, there is no caller for them to be thrown to and by default they are ignored.
In applications that use the asynchronous interface, and where it is important to deal with every issue that occurs in using AMPS, you can set an ExceptionHandler
via Client.set_exception_listener()
that receives these otherwise unhandled exceptions. Making the modifications shown in the example below, to our previous example, will allow those exceptions to be caught and handled. In this case we are simply printing those caught exceptions out to the console.
In some cases, the AMPS Python client may wrap exceptions of unknown type into an AMPSException
. Your application should always include an except block for AMPSException
.
If your application will attempt to recover from an exception thrown on the background processing thread, your application should set a flag and attempt recovery on a different thread than the thread that called the exception listener.
At the point that the AMPS client calls the exception listener, it has handled the exception. Your exception listener must not rethrow the exception (or wrap the exception and throw a different exception type).
In this example we have added a call to client.set_exception_listener()
, registering a simple function that writes the text of the exception out to the console. If exceptions are thrown in the message handler, those exceptions are written to the console.
AMPS records the stack trace and provides it to the exception handler, if the provided method includes a parameter for the stack trace. The sample below demonstrates one way to do this. (For sample purposes, the message handler always throws an exception.)
The AMPS client interface provides the ability to set one or more connection state listeners. A connection state listener is a callback that is invoked when the AMPS client detects a change to the connection state.
A connection state listener may be called from the client receive thread. An application should not submit commands to AMPS from a connection state listener, or the application risks creating a deadlock for commands that wait for acknowledgement from the server.
The AMPS client provides the following state values for a connection state listener:
Connected
The client has established a connection to AMPS. If you are using a Client
, this is delivered when connect()
is successful.
If you are using an HAClient
, this state indicates that the connect
part of the connect and logon process has completed. An HAClient
using the default disconnect handler will attempt to log on immediately after delivering this state.
Most applications that use Client
will attempt to log on immediately after the call to connect()
returns.
An application should not submit commands to AMPS from the connection state listener while the client is in this state unless the application knows that the state has been delivered from a Client
and that the Client
does not call logon()
.
LoggedOn
The client has successfully logged on to AMPS. If you are using a Client
, this is delivered when logon()
is successful.
If you are using an HAClient
, this state indicates that the logon
part of the connect and logon process has completed.
This state is delivered after the client is logged on, but before recovery of client state is complete. Recovery will continue after delivering this state: the application should not submit commands to AMPS from the connection state listener while the client is in this state if further recovery will take place.
HeartbeatInitiated
The client has successfully started heartbeat monitoring with AMPS. This state is delivered if the application has enabled heartbeating on the client.
This state is delivered before recovery of the client state is complete. Recovery may continue after this state is delivered. The application should not submit commands to AMPS from the connection state listener until the client is completely recovered.
PublishReplayed
Delivered when a client has completed replay of the publish store when recovering after connecting to AMPS.
This state is delivered when the client has a PublishStore configured.
If the client has a subscription manager set, (which is the default for an HAClient
), the application should not submit commands from the connection state listener until the Resubscribed
state is received.
Resubscribed
Delivered when a client has re-entered subscriptions when recovering after connecting to AMPS.
This state is delivered when the client has a subscription manager set (which is the default for an HAClient
). This is the final recovery step. An application can submit commands to AMPS from the connection state listener after receiving this state.
Disconnected
The client is not connected. For an HAClient
, this means that the client will attempt to reconnect to AMPS. For a Client
, this means that the client will invoke the disconnect handler, if one is specified.
Shutdown
The client is shut down. For an HAClient
, this means that the client will no longer attempt to reconnect to AMPS. This state is delivered when close()
is called on the client or when a server chooser tells the HAClient
to stop reconnecting to AMPS.
The enumeration provided for the connection state listener also includes a value of UNKNOWN
, for use as a default or to represent additional states in a custom Client
implementation. The 60East implementations of the client do not deliver this state.
The following table shows examples of the set of states that will be delivered during connection, in order, depending on what features of the client are set. Notice that, for an instance of the Client
class, this table assumes that the application calls both connect()
and logon()
. For an HAClient
, this table assumes that the HAClient
is using the default DisconnectHandler
for the HAClient
.
subscription manager
publish store
Connected
LoggedOn
PublishReplayed
Resubscribed
subscription manager
publish store
heartbeat set
Connected
LoggedOn
HeartbeatInitiated
PublishReplayed
Resubscribed
subscription manager
Connected
LoggedOn
Resubscribed
subscription manager
heartbeat set
Connected
LoggedOn
HeartbeatInitiated
Resubscribed
(default Client
configuration)
Connected
LoggedOn