Skip to content

Loading…

Concurrent batching support for client #6

Closed
wants to merge 2 commits into from

2 participants

@kyledrake

Please do not merge this until I give an OK. I did this on the plane and haven't got gotten a chance to test it with the live API yet.

The client can now be batched to run multiple requests concurrently. If you have to make a lot of API calls (for example, to get balances for a lot of users simultaneously), this will improve performance significantly. Under the hood, it uses internal threading to take advantage of Ruby's non-blocking IO model (one IO request per thread):

buy_price, sell_price = coinbase.batch do |client|
  client.buy_price 1
  client.sell_price 1
end

buy_price.inspect # => #<Money fractional:1384 currency:USD>
@kyledrake

Can I get some traction on this? I'm cleaning up my Github account and I want to remove my coinbase-ruby fork.

@lian

yup, like we discussed at the conference, i pushed it to https://github.com/coinbase/coinbase-ruby/branches

@lian lian closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Showing with 89 additions and 0 deletions.
  1. +13 −0 README.md
  2. +1 −0 lib/coinbase.rb
  3. +44 −0 lib/coinbase/batch.rb
  4. +6 −0 lib/coinbase/client.rb
  5. +25 −0 spec/client_spec.rb
View
13 README.md
@@ -221,6 +221,19 @@ coinbase.get('/account/balance').to_hash
Or feel free to add a new wrapper method and submit a pull request.
+## Batching
+
+The client can be batched to run multiple requests concurrently. If you have to make a lot of API calls (for example, to get balances for a lot of users simultaneously), this will improve performance significantly. Under the hood, it uses internal threading to take advantage of Ruby's non-blocking IO model (one IO request per thread):
+
+```ruby
+buy_price, sell_price = coinbase.batch do |client|
+ client.buy_price 1
+ client.sell_price 1
+end
+
+buy_price.inspect # => #<Money fractional:1384 currency:USD>
+```
+
## Security Notes
If someone gains access to your API Key they will have complete control of your Coinbase account. This includes the abillity to send all of your bitcoins elsewhere.
View
1 lib/coinbase.rb
@@ -3,3 +3,4 @@
require "coinbase/version"
require "coinbase/money"
require "coinbase/client"
+require "coinbase/batch"
View
44 lib/coinbase/batch.rb
@@ -0,0 +1,44 @@
+require 'thread'
+
+module Coinbase
+ class Batch < BasicObject
+ MAXIMUM_CONCURRENT_REQUESTS = 10
+
+ def initialize(client, opts={}, &block)
+ @client = client
+ @commands = []
+ @opts = opts
+
+ instance_eval &block
+ end
+
+ def run
+ responses = []
+
+ until @commands.empty?
+ threads = []
+ commands = []
+
+ (@opts[:maximum_concurrent_requests] || MAXIMUM_CONCURRENT_REQUESTS).times do
+ break if @commands.empty?
+ commands << @commands.shift
+ end
+
+ commands.each do |c|
+ threads << ::Thread.new {
+ ::Thread.current[:resp] = @client.send c[0], *c[1]
+ }
+ end
+
+ threads.each {|t| t.join}
+ threads.each {|t| responses << t[:resp]}
+ end
+
+ responses
+ end
+
+ def method_missing(meth, args=[])
+ @commands << [meth, args]
+ end
+ end
+end
View
6 lib/coinbase/client.rb
@@ -141,6 +141,12 @@ def sell! qty
r
end
+ # Batching
+
+ def batch(&block)
+ Batch.new(self, &block).run
+ end
+
# Wrappers for the main HTTP verbs
def get(path, options={})
View
25 spec/client_spec.rb
@@ -150,6 +150,31 @@
r.transfer.btc.should == 1.to_money
end
+ it "should batch multiple requests" do
+ buy_api_return = {"amount"=>"13.84", "currency"=>"USD"}
+ sell_api_return = {"amount"=>"15.00", "currency"=>"CAD"}
+ fake :get, "/prices/buy", buy_api_return
+ fake :get, "/prices/sell", sell_api_return
+
+ buy_price, sell_price = @c.batch do |c|
+ c.buy_price 1
+ c.sell_price 1
+ end
+
+ buy_price.to_f.should == 13.84
+ sell_price.to_f.should == 15.00
+
+ # Check to make sure the thread throttle doesn't cause an error
+
+ prices = @c.batch do |c|
+ (Coinbase::Batch::MAXIMUM_CONCURRENT_REQUESTS).times { c.buy_price(1); c.sell_price(1) }
+ end
+
+ prices.length.should == 20
+
+ prices.first.to_f.should == 13.84
+ prices.last.to_f.should == 15.00
+ end
private
Something went wrong with that request. Please try again.