Asynchronous HTTP requests with ruby - ruby

I have a rabbitmq queue full of requests and I want to send the requests as an HTTP GET asynchronously, without the need to wait for each request response. now I'm confused of what is better to use, threads or just EM ? The way i'm using it at the moment is something like the following , but it would be great to know if there is any better implementation with better performance here since it is a very crucial part of the program :
AMQP.start(:host => "localhost") do |connection|
queue = MQ.queue("some_queue")
queue.subscribe do |body|
EventMachine::HttpRequest.new('http://localhost:9292/faye').post :body => {:message => body.to_json }
end
end
With the code above, is the system will wait for each request to finish before starting the next one ? and if there any tips here I would highly appreciate it

HTTP is synchronous so you have to wait for the replies. If you want to simulate an async environment that you could have a thread pool and pass each request to a thread which will wait for the reply, then go back in the pool until the next request. You would either send the thread a callback function to use when the reply is finished or you would immediately return a future reply object, which allows you to put off waiting for the reply until you actually need the reply data.
The other way is to have a pool of processes each one of which is processing a request, waiting for the reply, etc.
In both cases, you have to have a pool that is big enough or else you will still end up waiting some of the time.

Related

Handling Asynchronous API Call in Jmeter

I am using Jmeter for functional Testing, below is a problem that I am facing and need some help/suggestion on how to overcome that.
I have a thread-group that consists of 2 requests, 1st is API call and 2nd is sending message to Active MQ.
Now the flow is that I need to do first the API call (this will wait for response), then send the message to a particular Active MQ queue and then only I will get the response for the API.
But since jmeter does sequential execution of requests, its get stuck at the API call waiting for the reply and never executes the second part.
I worked on the below solution but even that did not help.
1 Use a parallel controller and put both the API and ACtive MQ call under the same.
2 Add a Timer to the Active MQ call, so that it just did after the API call (2 Sec)
But when I checked in details I see that both the requests are sent at the same time and the timer does not come into effect anywhere.
Any way I can handle this scenario?
Please note I will get a response to the API only when I send message to the particular Active MQ Queue, else it will timeout in a minute.
Your Parallel Controller approach will work, however you need to amend the configuration a little bit, something like:
You could put your ActiveMQ Request under a different Thread Group and use Inter-Thread Communication Plugin for synchronization between threads
You can keep the current setup but replace the JMS Sampler with the JSR223 Sampler and send the message to ActiveMQ programmatically:
Textual code representation for your convenicence:
sleep(2000)
def connectionFactory = new org.apache.activemq.ActiveMQConnectionFactory('your activemq URL')
def connection = connectionFactory.createConnection()
connection.start()
def session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)
def destination = session.createQueue('your queue name')
def producer = session.createProducer(destination)
def message = session.createTextMessage('your message body')
producer.send(message)
connection.close()
For your Problem statement, following design will work.
Use 2 Thread Groups, add API call to first Thread group and Message to Active MQ call to second Thread Group
Add a delay to second Thread Group so that it should not run before first Thread Group
Run Test Plan
Use while controller. It will keep on executing till the desired outcome then the next request will be executed.
Hope this helps.
Update:-
While Loop controller execute its samplers until the condition specified is not set to False. The condition can be any variable or function that eventually evaluates to the string 'false'.
So, you need to specify a variable or function in While Loop, that has value 'true' and becomes 'false' somewhere else in the script. Once it changes to 'false', JMeter will exit the While loop.
For example if you are using a X-Path extractor in your script which have a variable named Status and its value changes from 'Start' to 'Finish' during the execution and you want to execute your script till 'Finish' has not been met, then you can use the expression ${__javaScript("'${imp_Status}'!='finish'",)} in your While loop and it will execute the samplers under While controller till the status = finish is met.
It is sort of polling based on certain condition. In your first API reponse, consider one value to be appear as the condition upon which first api call is successful.
It sounds that you just need to define timeout for HTTP Request,
If you define Response Timeout as 60000 (milliseconds), and it will only wait for a minute and then continue to next request
Connect Timeout Connection Timeout. Number of milliseconds to wait for a connection to open. No
Response Timeout Response Timeout. Number of milliseconds to wait for a response. Note that this applies to each wait for a response. If the server response is sent in several chunks, the overall elapsed time may be longer than the timeout.

CAF Receiver, shutdown handling to http requests

Some background reading at first :) what is shutdown handling
I'm doing a custom receiver with CAF SDK.
With the similar shutdown handling, I try to dispatch some http requests within the callback like:
receiver.addEventListener(
cast.framework.system.EventType.SHUTDOWN,
e => {
// some http requests
HttpHandler.post(url, somePayload);
HttpHandler.post(anotherUrl, someOtherPayload);
....... (more requests to go)
});
However, I can't guarantee those requests are reaching the destination since the receiver application is about to terminate anytime(Likely less than 1 sec).Those requests were also proved not reaching the destination in fact.
As far as I know, there is no way to postpone the shutdown of the receiver application with CAF SDK itself.
Is there a workaround about it? Is there a way we can postpone shutdown with the help of CAF SDK?
I did some more research, and it turns out you can also use
window.addEventListener("beforeunload", e => {
...
});
instead of
receiver.addEventListener(
cast.framework.system.EventType.SHUTDOWN,
e => {
...
});
Alas, this does not help to assure everything in the callback is executed: the beforeunload callback is terminated in the same way as the shutdown handler.
The answer seems quite simple: turn all http requests to synchronous.
Drawbacks are quite obvious as well, synchronous requests will block the thread. When one request is hung in middle of somewhere due to unknown reasons, the script will be blocked forever unless force shutdown.
Still looking for better way to improve it.

Using Eventmachine http request in a Sidekiq worker

So lets say I have a sidekiq process that sends off a http post request that I don't want to wait for. I don't want this to be a blocker on the speed of the workers.
One idea I have is to use this simple sample code for EventMachine Http Request
EventMachine.run do
http = EventMachine::HttpRequest.new("http://www.example.com").post :options => {...}
http.callback do
puts "got a response"
puts http.response
EventMachine.stop
end
puts "worker finished"
end
so lets assume my worker process finishes before the callback is called. What will happen here? does this mean the pointer to the call back will fail? I'd like to understand the flow of control here.
Depending on what you need:
You want to utilize CPU
Sidekiq workers are very lightweight. You can run more of them to utilize CPU while waiting responce.
You want workers to finish faster.
You can enqueue each request to be proccessed by different worker. It will be like next_tick() in EM.
I'm excited about Sidekiq and Celluloid because it changes the way we think. http://www.slideshare.net/KyleDrake/hybrid-concurrency-patterns?utm_source=rubyweekly&utm_medium=email
The EventMachine.run block will not return until you call EventMachine.stop. So, on your case, the worker won't finish without the callback being run.

Elegant way to stop socket read operation from outside

I implemented a small client server application in Ruby and I have the following problem: The server starts a new client session in a new thread for each connecting client, but it should be possible to shutdown the server and stop all the client sessions in a 'polite' way from outside without just killing the thread while I don't know which state it is in.
So I decided that the client session object gets a `stop' flag which can be set from outside and is checked before each action. The problem is that it should not wait for the client, if it is just waiting for a request. I have the following temporary solution:
def read_client
loop do
begin
timeout(1) { return #client.gets }
rescue Timeout::Error
if #stop
stop # Notifies the client and closes the connection
return nil
end
end
end
end
But that sucks, looks terrible and intuitively, this should be such a normal thing that there has to be a `normal' solution to it. I don't even know if it is safe or if it could happen that the gets operation reads part of the client request, but not all of it.
Another side question is, if setting/getting a boolean flag is an atomic operation in Ruby (or if I need an additional Mutex for the flag).
Thread-per-client approach is usually a disaster for server design. Also blocking I/O is difficult to interrupt without OS-specific tricks. Check out non-blocking sockets, see for example, answers to this question.

Block TCP-send till ACK returned

I am programming a client application sending TCP/IP packets to a server. Because of timeout issues I want to start a timer as soon as the ACK-Package is returned (so there can be no timeout while the package has not reached the server). I want to use the winapi.
Setting the Socket to blocking mode doesn't help, because the send command returns as soon as the data is written into the buffer (if I am not mistaken). Is there a way to block send till the ACK was returned, or is there any other way to do this without writing my own TCP-implementation?
Regards
It sounds like you want to do the minimum implementation to achieve your goal. In this case you should set your socket to blocking, and following the send which blocks until all data is sent, you call recv which in turn will block until the ACK packet is received or the server end closes or aborts the connection.
If you wanted to go further with your implementation you'd have to structure your client application in such a way that supports asynchronous communication. There are a few techniques with varying degrees of complexity; polling using select() simple, event model using WSASelectEvent/WSAWaitForMultipleEvents challenging, and the IOCompletionPort model which is very complicated.
peudocode... Will wait until ack is recevied, after which time you can call whatever functionallity you want -i chose some made up function send_data.. which would then send information over the socket after receiving the ack.
data = ''
while True
readable, writable, errors = select([socket])
if socket in readble
data += recv(socket)
if is_ack(data)
timer.start() #not sure why you want this
break
send_data(socket)

Resources