What have you found for these years?

2012-10-31

rest-core and rest-more 2.0.0 released, and more

rest-core is Modular Ruby clients interface for REST APIs.
rest-more is Various REST clients such as Facebook and Twitter built with rest-core.

So finally I've made up my mind that I should be definitely determined to make this happen
no matter how I was so unmotivated and tired to finish writing READMEs, rest-core and
rest-more 2.0 should definitely be released before the upcoming rubyconf.tw/2012 arrived.

Because, even though my topic is about concurrent Ruby application servers, it's actually
about concurrency in general, and rest-core 2.0 is a very important ground for me to
base my thoughts (or theory if you can take that). I am still not sure how to draw the
picture clearly, but it would be good if a stable version would be released at that point,
and people can read a clear README for rest-core to understand them more easily.

I am not saying I've put that clear now, but at least it'd better to start soon, so I released
it regardless it's good or not. After all, README is the only thing missing to release 2.0!
Hey, we've been running 2.0 on pic-collage.com for months, it should be quite stable as
it runs quite smooth to me. There's no excuse to not release 2.0 before rubyconf.tw/2012.

It took me quite a few hours to finish those READMEs though. I guess I am just so bad
at writing documents. I am only good at throwing random thoughts or words murmuring
and mumbling around, if quantity is the only measurement for quality...

Anyway, I am a bit exhausted and cannot play GuildWars2. What? Did I mention GuildWars2?

I won't paste all the words I'd written in CHANGES.md and README.md, they are simply
too much. Please go and see on Github instead of my blog, but here I would paste the
most important section here, because this is the whole point of moving to rest-core 2.0.

* * *

Advanced Concurrent HTTP Requests -- Embrace the Future


The Interface

There are a number of different ways to make concurrent requests in
rest-core. They could be roughly categorized to two different forms.
One is using the well known callbacks, while the other one is using
through a technique called future. Basically, it means it would
return you a promise, which would eventually become the real value
(response here) you were asking for whenever you really want it.
Otherwise, the program keeps running until the value is evaluated,
and blocks there if the computation (response) hasn't been done yet.
If the computation is already done, then it would simply return you
the result.

Here's a very simple example for using futures:
require 'rest-core'
YourClient = RC::Builder.client do
  use RC::DefaultSite , 'https://api.github.com/users/'
  use RC::JsonResponse, true
  use RC::CommonLogger, method(:puts)
end

client = YourClient.new
puts "rest-client with threads doing concurrent requests"
a = [client.get('cardinalblue'), client.get('godfat')]
puts "It's not blocking... but doing concurrent requests underneath"
p a.map{ |r| r['name'] } # here we want the values, so it blocks here
puts "DONE"

And here's a corresponded version for using callbacks:
require 'rest-core'
YourClient = RC::Builder.client do
  use RC::DefaultSite , 'https://api.github.com/users/'
  use RC::JsonResponse, true
  use RC::CommonLogger, method(:puts)
end

client = YourClient.new
puts "rest-client with threads doing concurrent requests"
client.get('cardinalblue'){ |v|
         p v['name']
       }.
       get('godfat'){ |v|
         p v['name']
       }
puts "It's not blocking... but doing concurrent requests underneath"
client.wait # until all requests are done
puts "DONE"

You can pick whatever works for you.

What Concurrency Model to Choose?


In the above example, we're using rest-client with threads, which works
for most of cases. But you might also want to use em-http-request with
EventMachine, which is using a faster HTTP parser. In theory, it should
be much more efficient than rest-client and threads.

To pick em-http-request, you must run the requests inside the EventMachine's
event loop, and also wrap your request with either a thread or a fiber,
because we can't block the event loop and ask em-http-request to finish
its job making requests.

Here's an example of using em-http-request with threads:
require 'em-http-request'
require 'rest-core'
YourClient = RC::Builder.client do
  use RC::DefaultSite , 'https://api.github.com/users/'
  use RC::JsonResponse, true
  use RC::CommonLogger, method(:puts)
end

client = YourClient.new
puts "eventmachine with threads doing concurrent requests"
EM.run{
  Thread.new{
    a = [client.get('cardinalblue'), client.get('godfat')]
    p a.map{ |r| r['name'] } # here we want the values, so it blocks here
    puts "DONE"
    EM.stop
  }
  puts "It's not blocking... but doing concurrent requests underneath"
}

And here's an example of using em-http-request with fibers:
require 'fiber'           # remember to require fiber first,
require 'em-http-request' # or rest-core won't pick fibers
require 'rest-core'
YourClient = RC::Builder.client do
  use RC::DefaultSite , 'https://api.github.com/users/'
  use RC::JsonResponse, true
  use RC::CommonLogger, method(:puts)
end

client = YourClient.new
puts "eventmachine with fibers doing concurrent requests"
EM.run{
  Fiber.new{
    a = [client.get('cardinalblue'), client.get('godfat')]
    p a.map{ |r| r['name'] } # here we want the values, so it blocks here
    puts "DONE"
    EM.stop
  }
  puts "It's not blocking... but doing concurrent requests underneath"
}

As you can see, both of them are quite similar to each other, because the
idea behind the scene is the same. If you don't know what concurrency model
to pick, start with rest-client since it's the easiest one to setup.

A full runnable example is at: example/multi.rb. If you want to know
all the possible use cases, you can also see: example/use-cases.rb. It's
also served as a test for each possible combinations, so it's quite complex
and complete.

0 retries:

Post a Comment

Note: Only a member of this blog may post a comment.



All texts are licensed under CC Attribution 3.0