Summary
C/C++ applications that use WireAPI to do AMQP work need to handle interrupts like Ctrl-C in some fashion. This tutorial explains how to write a WireAPI application that properly detects an interrupt and shuts down gracefully.
Problem
Any C/C++ application needs to handle signals like SIGINT (Ctrl-C) gracefully. WireAPI captures signals, so these don't get passed to the application. If you write a naive application you can find that your code never exits when you use Ctrl-C - and you need to explicitly kill the process with a SIGTERM (kill -9).
The following example shows the problem. You can compile this and run it (with a broker running locally), then press Ctrl-C. The program never exits:
#include "base.h"
#include "amq_client_connection.h"
#include "amq_client_session.h"
int main (int argc, char *argv [])
{
amq_client_connection_t
*connection;
icl_longstr_t
*auth_data;
// Initialise system
icl_system_initialise (argc, argv);
// Open a connection
auth_data = amq_client_connection_auth_plain ("guest", "guest");
connection = amq_client_connection_new (
"localhost", "/", auth_data, "loop example", 0, 30000);
assert (connection);
icl_longstr_destroy (&auth_data);
FOREVER {
sleep (1);
}
// Close the connection
amq_client_connection_destroy (&connection);
// Uninitialise system
icl_system_terminate ();
exit (0);
}
Explanation
If you trace the code, you will see that it simply loops for ever in this block:
FOREVER {
sleep (1);
}
To make the code work properly we need to do two things:
- Check the health of the connection and exit the loop if the connection dies.
- Call the WireAPI connection wait method instead of doing a sleep() call.
Let's take these one at a time. First, checking the health of the connection:
FOREVER {
sleep (1);
if (!connection->alive)
break;
}
When we compile and run the code now, we see that it does actually exit when we press Ctrl-C. What is going on? In fact WireAPI is detecting the interrupt, correctly shutting down, and setting the connection alive flag to zero.
However, we see that the application still sleeps for a second between checks. So when we press Ctrl-C it responds only after a short delay (average half a second, of course).
WireAPI provides a smart sleep method, called wait, which does several useful things:
- It pauses the application.
- It returns as soon as something interesting happens - e.g. a message arrives, or the connection closes.
- In single-threaded builds, it lets WireAPI operate.
In fact, without doing wait calls, your application won't work properly in a single-threaded environment since the sleep() calls will block the whole application, including WireAPI.
When we add the wait call - using a 1-second wait - we get this:
FOREVER {
amq_client_connection_wait (connection, 1000);
if (!connection->alive)
break;
}
The program now works properly and responds immediately to a Ctrl-C.
Comments
Author
- Pieter Hintjens <moc.xitami|hp#moc.xitami|hp>
