Behaviour of beast boost Async http client in single threaded asynchronous system when multiple simultaneous requests are sent - c++

How does beast boost async http client works in c++11 when multiple simultaneous requests are made in a single threaded asynchronous system?
USE CASE:
I want to send multiple simultaneous asynchronous requests and I am creating new http client for each request. When response of any request is received then I am calling a callback function which deletes the client after 1 sec of the response received to avoid any memory leaks. But it appears that the system/ code hangs in between after some random number of simulatneous http requests even though I create a new client object for each request. Does beast boost use some shared resource as this pause looks like system is in an infinite deadlock. PS: I also tried commenting this delete block but then also system behaves the same.
Below are the specifications for the boost and compiler version:
boost: stable 1.68.0
BOOST_BEAST_VERSION 181
clang -v
clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
void sendHttpRequest(){
HttpClient *client = new HttpClient();
deleteClient = [this,client]{
int timeout = 1;
boost::asio::deadline_timer *clientDeleteTimer = new boost::asio::deadline_timer( *this->context);
clientDeleteTimer->expires_from_now(boost::posix_time::seconds(timeout));
clientDeleteTimer->async_wait([client,this,clientDeleteTimer](const boost::system::error_code &ec){
if(ec == boost::asio::error::operation_aborted){
std::cout<<" Operation aborted\n"<<std::flush;
return;
}
else{
delete client;
}
delete clientDeleteTimer;
};
callback = [] {
std::cout<<"Response recieved successfully\n"<<std::flush;
deleteClient();
};
errback = [] {
std::cout<<"Response not recieved \n"<<std::flush;
deleteClient();
};
client.sendPostRequest(request, callback , errback);
}
this function above is a wrapper function which will be called for each request and internally will create new http async client and delete that client object after 1 sec of response / error is recieved (basically the request has been processed).

Visit https://github.com/boostorg/beast/issues/1458 .This issue also address the same issue. But i guess still its unresolved.

Related

using the boost asio server session from another thread

I have written a threaded server much like this one: https://www.boost.org/doc/libs/1_36_0/doc/html/boost_asio/example/echo/async_tcp_echo_server.cpp
And a client: https://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/example/timeouts/blocking_tcp_client.cpp
They seem to work fine together when the client is talking directly with the server session. But now I would like to create another thread that would use the servers ioservice to send small messages. How would this be possible? I have read that shared_ptr would be one option, but have not got it working...
Inside the session class I define:
typedef boost::shared_ptr<session> session1;
static session1 create(boost::asio::io_service& io_service)
{
return session1(new session(io_service));
}
Then I define a global session_ptr as
session::session1 new_session1 = nullptr;
Then in the acceptor I start the session as:
new_session1 = session::create(tcp_io_serviceServer);
acceptor_.listen();
acceptor_.async_accept(new_session1->socket(), boost::bind(&server::handle_accept, this, boost::asio::placeholders::error));
and in the handle_accept:
new_session1->start();
Now what I would like to achieve, is that when the async_read of the server session gets a message from client to start a new thread:
if (dataReceived[0] == _dataStartCameraThread)
{
pthread = boost::thread(boost::bind(StartProcess, server));
}
then in that thread I want to send messages to the client as: new_session1->write1(error) as
void write1(const boost::system::error_code& error)
{
boost::asio::async_write(tcpsocket, boost::asio::buffer(sbuf, 1), boost::bind(&session::handle_dummy, this, boost::asio::placeholders::error));
}
But without the shared_ptr approach I cannot make this work. It claims that the file handle is not valid.
And using the shared_ptr approach I cannot seem to write anything from the server side, I can only read:
write failed. The file handle supplied is not valid
I checked that the socket is closed even though it just received the message.
Any suggestions where I should go here?
Thank you!

Using third party http client on Armeria

I'm discovering Armeria framework and I want to consume a REST service.
Using the Armeria WebClient:
WebClient webClient = WebClient.of("http://localhost:9090");
RequestHeaders getJson = RequestHeaders.of(HttpMethod.GET, "/some-service",
HttpHeaderNames.CONTENT_TYPE, "application/json", "SomeHeader", "armeriaTest");
return webClient.execute(getJson).aggregate().thenApply(resp->{
if(HttpStatus.OK.equals(resp.status())) {
return parseBody(resp.contentUtf8());
}else if(HttpStatus.BAD_REQUEST.equals(resp.status())){
throw new IllegalStateException("not exists");
}
throw new RuntimeException("Error");
});
This code returns a CompletionStage that will be resolved asynchronously, because if I do a join() or get() right here causes an "java.lang.IllegalStateException: Blocking event loop, don't do this."
My question is: What if I want to use a third party httpclient library (like Apache HttpClient) instead the Web?
The client call should be wrapped in a Future too?
How should I manage the client requests to fit in the framework approach and avoid the "Blocking event loop" issue?
Thanks to all!
Yes. You should never perform any blocking operations when your code is running in an event loop thread. You can perform a blocking operation by submitting it to other thread pool dedicated to handling blocking operations.
If you are using Armeria on the server side, you can get one via ServiceRequestContext.blockingTaskExecutor():
Server server = Server
.builder()
.service("/", (ctx, req) -> {
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> {
// Perform some blocking operations that return a string.
}, ctx.blockingTaskExecutor());
CompletableFuture<String> f2 = f1.thenApply(result -> {
// Transform the result into an HttpResponse.
return HttpResponse.of("Result: %s", result);
});
return HttpResponse.from(f2);
})
.build();
If you are not using Armeria on the server side, you can use other Executor provided by your platform, or you can even create a new ThreadPoolExecutor dedicated to handling blocking operations.

detect client connection closed in the grpc server

In the unary RPC example provided in the grpc Github (client) and (server), is there any way to detect client's closed connection?
For example, in server.cc file:
std::string prefix("Hello ");
reply_.set_message(prefix + request_.name());
// And we are done! Let the gRPC runtime know we've finished, using the
// memory address of this instance as the uniquely identifying tag for
// the event.
status_ = FINISH;
int p = 0,i=0;
while(i++ < 1000000000) { // some dummy work
p = p + 10;
}
responder_.Finish(reply_, Status::OK, this);
With this dummy task before sending the response back to the client, server will take a few seconds. If we close the client (for example say with Ctrl+C), the server does not throw any error. It simply calls Finish and then deallocates the object as if the Finish is successful.
Is there any async feature (handler function) on the server-side to get us notified that the client has closed the connection or client is terminated?
Thank You!
Unfortunately, no.
But now guys from gRPC team works hard to implement callback mechanism into C++ implementation. As I understand it will work the same way as on Java implementation( https://youtu.be/5tmPvSe7xXQ?t=1843 ).
You can see how to work with future API with next examples: client_callback.cc and server_callback.cc
And the point of your interest there is ServerBidiReactor class from ::grpc::experimental namespace for server side. It have OnDone and OnCancel notification methods that maybe can help you.
Another interesting point there is that you can store a pointers to connection object and send notifications to client at any time.
But it still have many issue and I don't recommend to use this API in production code.
Current progress of C++ callbacks implementation you can see there: https://github.com/grpc/grpc/projects/12#card-12554506

Windows::Web::Http::HttpClient - Renegotiate SSL handshake

As part of the my Windows phone app, I use Windows::Web::Http::HttpClient to post requests to the server. I tried -
void sendRequest(HttpRequestMessage^ httpReqMsg)
{
HttpBaseProtocolFilter^ httpFilter = ref new HttpBaseProtocolFilter();
httpFilter->CacheControl->WriteBehavior = HttpCacheWriteBehavior::NoCache;
HttpClient^ httpClient = ref new HttpClient(httpFilter);
try
{
// Post the request
auto httpProgress = httpClient->SendRequestAsync(httpReqMsg);
// Handle the http progress and it's response messages
// ...
}
catch(Exception^ ex)
{
// ...
}
} // httpFilter, httpClient are auto released
When httpFilter, httpClient falls out of scope, I expect underlying sockets and memory resources should be released. During the call HttpClient::SendRequestAsync, I see SSL negotiation happening for the first time. Any further calls to sendRequest function, isn't triggering full handshake.
I amn't allowed to load any DLLs to explicity clear the SSL cache (SslEmptyCache). Isn't my assumption correct that full handshake should happen on every call to sendRequest function ? If not, how to achieve full SSL handshake ? Thanks.

ActiveMQ-cpp Broker URI with PrefetchPolicy has no effect

I am using activemq-cpp 3.7.0 with VS 2010 to build a client, the server is ActiveMQ 5.8. I have created a message consumer using code similar to the following, based on the CMS configurations mentioned here. ConnClass is a ExceptionListener and a MessageListener. I only want to consume a single message before calling cms::Session::commit().
void ConnClass::setup()
{
// Create a ConnectionFactory
std::tr1::shared_ptr<ConnectionFactory> connectionFactory(
ConnectionFactory::createCMSConnectionFactory(
"tcp://localhost:61616?cms.PrefetchPolicy.queuePrefetch=1");
// Create a Connection
m_connection = std::tr1::shared_ptr<cms::Connection>(
connectionFactory->createConnection());
m_connection->start();
m_connection->setExceptionListener(this);
// Create a Session
m_session = std::tr1::shared_ptr<cms::Session>(
m_connection->createSession(Session::SESSION_TRANSACTED));
// Create the destination (Queue)
m_destination = std::tr1::shared_ptr<cms::Destination>(
m_session->createQueue("myqueue?consumer.prefetchSize=1"));
// Create a MessageConsumer from the Session to the Queue
m_consumer = std::tr1::shared_ptr<cms::MessageConsumer>(
m_session->createConsumer( m_destination.get() ));
m_consumer->setMessageListener( this );
}
void ConnClass::onMessage( const Message* message )
{
// read message code ...
// schedule a processing event for
// another thread that calls m_session->commit() when done
}
The problem is I am receiving multiple messages instead of one message before calling m_session->commit() -- I know this because the commit() call is triggered by user input. How can I ensure onMessage() is only called once before each call to commit()?
It doesn't work that way. When using async consumers the messages are delivered as fast as the onMessage method completes. If you want to consume one and only one message then use a sync receive call.
For an async consumer the prefetch allows the broker to buffer up work on the client instead of firing one at a time so you can generally get better proformance, in your case as the async onMessage call completes an ack is sent back to the broker an the next message is sent to the client.
Yes, I find this too. However, when I use the Destination URI option ( "consumer.prefetchSize=15" , http://activemq.apache.org/cms/configuring.html#Configuring-DestinationURIParameters ) for the asynchronous consumer, It works well.
BTW, I just use the latest ActiveMQ-CPP v3.9.4 by Tim , and ActiveMQ v5.12.1 on CentOS 7.
Thanks!