em-synchrony 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +92 -0
 - data/Rakefile +20 -0
 - data/VERSION +1 -0
 - data/lib/em-synchrony.rb +13 -0
 - data/lib/em-synchrony/connection_pool.rb +83 -0
 - data/lib/em-synchrony/em-http.rb +18 -0
 - data/lib/em-synchrony/em-jack.rb +30 -0
 - data/lib/em-synchrony/em-multi.rb +37 -0
 - data/lib/em-synchrony/em-mysql.rb +18 -0
 - data/lib/em-synchrony/em-remcached.rb +67 -0
 - data/spec/beanstalk_spec.rb +41 -0
 - data/spec/connection_pool_spec.rb +129 -0
 - data/spec/helper/all.rb +16 -0
 - data/spec/helper/stub-http-server.rb +22 -0
 - data/spec/helper/tolerance_matcher.rb +40 -0
 - data/spec/http_spec.rb +51 -0
 - data/spec/mysql_spec.rb +93 -0
 - data/spec/remcached_spec.rb +51 -0
 - metadata +100 -0
 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,92 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # EM-Synchrony
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Collection of convenience classes and patches to common EventMachine clients to 
         
     | 
| 
      
 4 
     | 
    
         
            +
            make them Fiber aware and friendly. Word of warning: even though fibers have been
         
     | 
| 
      
 5 
     | 
    
         
            +
            backported to Ruby 1.8.x, these classes assume Ruby 1.9 (if you're using fibers
         
     | 
| 
      
 6 
     | 
    
         
            +
            in production, you should be on 1.9 anyway) 
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            Features:
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
             * Fiber aware connection pool with sync/async query support
         
     | 
| 
      
 11 
     | 
    
         
            +
             * Multi request interface which accepts any callback enabled client
         
     | 
| 
      
 12 
     | 
    
         
            +
             * em-http-request: .get, etc are synchronous, while .aget, etc are async
         
     | 
| 
      
 13 
     | 
    
         
            +
             * em-mysqlplus: .query is synchronous, while .aquery is async
         
     | 
| 
      
 14 
     | 
    
         
            +
             * remcached: .get, etc, and .multi_* methods are synchronous
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            ## Example with async em-http client:
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            	EventMachine.run do
         
     | 
| 
      
 19 
     | 
    
         
            +
                  Fiber.new {
         
     | 
| 
      
 20 
     | 
    
         
            +
                    res = EventMachine::HttpRequest.new("http://www.postrank.com").get
         
     | 
| 
      
 21 
     | 
    
         
            +
            		
         
     | 
| 
      
 22 
     | 
    
         
            +
            		p "Look ma, no callbacks!"
         
     | 
| 
      
 23 
     | 
    
         
            +
            		p res
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    EventMachine.stop
         
     | 
| 
      
 26 
     | 
    
         
            +
                  }.resume
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            ## Example with multi-request async em-http client:
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            	EventMachine.run do
         
     | 
| 
      
 32 
     | 
    
         
            +
            	  Fiber.new {
         
     | 
| 
      
 33 
     | 
    
         
            +
            		
         
     | 
| 
      
 34 
     | 
    
         
            +
             	    multi = EventMachine::Synchrony::Multi.new
         
     | 
| 
      
 35 
     | 
    
         
            +
                    multi.add :a, EventMachine::HttpRequest.new("http://www.postrank.com").aget
         
     | 
| 
      
 36 
     | 
    
         
            +
                    multi.add :b, EventMachine::HttpRequest.new("http://www.postrank.com").apost
         
     | 
| 
      
 37 
     | 
    
         
            +
                    res = multi.perform
         
     | 
| 
      
 38 
     | 
    
         
            +
            	
         
     | 
| 
      
 39 
     | 
    
         
            +
            		p "Look ma, no callbacks, and parallel requests!"
         
     | 
| 
      
 40 
     | 
    
         
            +
            		p res
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            	    EventMachine.stop
         
     | 
| 
      
 43 
     | 
    
         
            +
            	  }.resume
         
     | 
| 
      
 44 
     | 
    
         
            +
            	end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            ## Example connection pool shared by a fiber:
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            	EventMachine.run do
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            	  db = EventMachine::Synchrony::ConnectionPool.new(size: 2) do
         
     | 
| 
      
 51 
     | 
    
         
            +
            	    EventMachine::MySQL.new(host: "localhost")
         
     | 
| 
      
 52 
     | 
    
         
            +
            	  end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            	  Fiber.new {
         
     | 
| 
      
 55 
     | 
    
         
            +
            	    start = now
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            	    multi = EventMachine::Synchrony::Multi.new
         
     | 
| 
      
 58 
     | 
    
         
            +
            	    multi.add :a, db.aquery("select sleep(1)")
         
     | 
| 
      
 59 
     | 
    
         
            +
            	    multi.add :b, db.aquery("select sleep(1)")
         
     | 
| 
      
 60 
     | 
    
         
            +
            	    res = multi.perform
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
            		p "Look ma, no callbacks, and parallel requests!"
         
     | 
| 
      
 63 
     | 
    
         
            +
            		p res
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            	    EventMachine.stop
         
     | 
| 
      
 66 
     | 
    
         
            +
            	  }.resume
         
     | 
| 
      
 67 
     | 
    
         
            +
            	end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
            # License
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
            (The MIT License)
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            Copyright (c) 2010 Ilya Grigorik
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
      
 76 
     | 
    
         
            +
            a copy of this software and associated documentation files (the
         
     | 
| 
      
 77 
     | 
    
         
            +
            'Software'), to deal in the Software without restriction, including
         
     | 
| 
      
 78 
     | 
    
         
            +
            without limitation the rights to use, copy, modify, merge, publish,
         
     | 
| 
      
 79 
     | 
    
         
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         
     | 
| 
      
 80 
     | 
    
         
            +
            permit persons to whom the Software is furnished to do so, subject to
         
     | 
| 
      
 81 
     | 
    
         
            +
            the following conditions:
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be
         
     | 
| 
      
 84 
     | 
    
         
            +
            included in all copies or substantial portions of the Software.
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
         
     | 
| 
      
 87 
     | 
    
         
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         
     | 
| 
      
 88 
     | 
    
         
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
         
     | 
| 
      
 89 
     | 
    
         
            +
            IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
         
     | 
| 
      
 90 
     | 
    
         
            +
            CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
         
     | 
| 
      
 91 
     | 
    
         
            +
            TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
         
     | 
| 
      
 92 
     | 
    
         
            +
            SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rake'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            begin
         
     | 
| 
      
 4 
     | 
    
         
            +
              require 'jeweler'
         
     | 
| 
      
 5 
     | 
    
         
            +
              Jeweler::Tasks.new do |gemspec|
         
     | 
| 
      
 6 
     | 
    
         
            +
                gemspec.name = "em-synchrony"
         
     | 
| 
      
 7 
     | 
    
         
            +
                gemspec.summary = "Fiber aware EventMachine libraries"
         
     | 
| 
      
 8 
     | 
    
         
            +
                gemspec.description = gemspec.summary
         
     | 
| 
      
 9 
     | 
    
         
            +
                gemspec.email = "ilya@igvita.com"
         
     | 
| 
      
 10 
     | 
    
         
            +
                gemspec.homepage = "http://github.com/igrigorik/em-synchrony"
         
     | 
| 
      
 11 
     | 
    
         
            +
                gemspec.authors = ["Ilya Grigorik"]
         
     | 
| 
      
 12 
     | 
    
         
            +
                gemspec.required_ruby_version = ">= 1.9"
         
     | 
| 
      
 13 
     | 
    
         
            +
                gemspec.add_dependency('eventmachine', '>= 0.12.9')
         
     | 
| 
      
 14 
     | 
    
         
            +
                gemspec.rubyforge_project = "em-synchrony"
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              Jeweler::GemcutterTasks.new
         
     | 
| 
      
 18 
     | 
    
         
            +
            rescue LoadError
         
     | 
| 
      
 19 
     | 
    
         
            +
              puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
    
        data/VERSION
    ADDED
    
    | 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            0.1.1
         
     | 
    
        data/lib/em-synchrony.rb
    ADDED
    
    | 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            $:.unshift(File.dirname(__FILE__) + '/../lib')
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "rubygems"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "eventmachine"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "fiber"
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require "em-synchrony/em-multi"
         
     | 
| 
      
 8 
     | 
    
         
            +
            require "em-synchrony/em-http"
         
     | 
| 
      
 9 
     | 
    
         
            +
            require "em-synchrony/em-mysql"
         
     | 
| 
      
 10 
     | 
    
         
            +
            # require "em-synchrony/em-jack"
         
     | 
| 
      
 11 
     | 
    
         
            +
            require "em-synchrony/em-remcached"
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            require "em-synchrony/connection_pool"
         
     | 
| 
         @@ -0,0 +1,83 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module EventMachine
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Synchrony
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                class ConnectionPool
         
     | 
| 
      
 5 
     | 
    
         
            +
                  def initialize(opts, &block)
         
     | 
| 
      
 6 
     | 
    
         
            +
                    @reserved  = {}   # map of in-progress connections
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @available = []   # pool of free connections
         
     | 
| 
      
 8 
     | 
    
         
            +
                    @pending   = []   # pending reservations (FIFO)
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                    opts[:size].times do
         
     | 
| 
      
 11 
     | 
    
         
            +
                      @available.push(block.call) if block_given?
         
     | 
| 
      
 12 
     | 
    
         
            +
                    end
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  # Choose first available connection and pass it to the supplied
         
     | 
| 
      
 16 
     | 
    
         
            +
                  # block. This will block indefinitely until there is an available
         
     | 
| 
      
 17 
     | 
    
         
            +
                  # connection to service the request.
         
     | 
| 
      
 18 
     | 
    
         
            +
                  def execute(async)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    f = Fiber.current
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 22 
     | 
    
         
            +
                      conn = acquire(f)
         
     | 
| 
      
 23 
     | 
    
         
            +
                      yield conn
         
     | 
| 
      
 24 
     | 
    
         
            +
                    ensure
         
     | 
| 
      
 25 
     | 
    
         
            +
                      release(f) if not async
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  private
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    # Acquire a lock on a connection and assign it to executing fiber
         
     | 
| 
      
 32 
     | 
    
         
            +
                    # - if connection is available, pass it back to the calling block
         
     | 
| 
      
 33 
     | 
    
         
            +
                    # - if pool is full, yield the current fiber until connection is available
         
     | 
| 
      
 34 
     | 
    
         
            +
                    def acquire(fiber)
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                      if conn = @available.pop
         
     | 
| 
      
 37 
     | 
    
         
            +
                        @reserved[fiber.object_id] = conn
         
     | 
| 
      
 38 
     | 
    
         
            +
                        conn
         
     | 
| 
      
 39 
     | 
    
         
            +
                      else
         
     | 
| 
      
 40 
     | 
    
         
            +
                        Fiber.yield @pending.push fiber
         
     | 
| 
      
 41 
     | 
    
         
            +
                        acquire(fiber)
         
     | 
| 
      
 42 
     | 
    
         
            +
                      end
         
     | 
| 
      
 43 
     | 
    
         
            +
                    end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    # Release connection assigned to the supplied fiber and
         
     | 
| 
      
 46 
     | 
    
         
            +
                    # resume any other pending connections (which will 
         
     | 
| 
      
 47 
     | 
    
         
            +
                    # immediately try to run acquire on the pool)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    def release(fiber)
         
     | 
| 
      
 49 
     | 
    
         
            +
                      @available.push(@reserved.delete(fiber.object_id))
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                      if pending = @pending.pop
         
     | 
| 
      
 52 
     | 
    
         
            +
                        pending.resume
         
     | 
| 
      
 53 
     | 
    
         
            +
                      end
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                    # Allow the pool to behave as the underlying connection
         
     | 
| 
      
 57 
     | 
    
         
            +
                    #
         
     | 
| 
      
 58 
     | 
    
         
            +
                    # If the requesting method begins with "a" prefix, then
         
     | 
| 
      
 59 
     | 
    
         
            +
                    # hijack the callbacks and errbacks to fire a connection
         
     | 
| 
      
 60 
     | 
    
         
            +
                    # pool release whenever the request is complete. Otherwise
         
     | 
| 
      
 61 
     | 
    
         
            +
                    # yield the connection within execute method and release
         
     | 
| 
      
 62 
     | 
    
         
            +
                    # once it is complete (assumption: fiber will yield until
         
     | 
| 
      
 63 
     | 
    
         
            +
                    # data is available, or request is complete)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    #
         
     | 
| 
      
 65 
     | 
    
         
            +
                    def method_missing(method, *args)
         
     | 
| 
      
 66 
     | 
    
         
            +
                      async = (method[0,1] == "a")
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                      execute(async) do |conn|
         
     | 
| 
      
 69 
     | 
    
         
            +
                        df = conn.send(method, *args)
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                        if async
         
     | 
| 
      
 72 
     | 
    
         
            +
                          fiber = Fiber.current
         
     | 
| 
      
 73 
     | 
    
         
            +
                          df.callback { release(fiber) }
         
     | 
| 
      
 74 
     | 
    
         
            +
                          df.errback { release(fiber) }
         
     | 
| 
      
 75 
     | 
    
         
            +
                        end
         
     | 
| 
      
 76 
     | 
    
         
            +
                        
         
     | 
| 
      
 77 
     | 
    
         
            +
                        df
         
     | 
| 
      
 78 
     | 
    
         
            +
                      end
         
     | 
| 
      
 79 
     | 
    
         
            +
                    end
         
     | 
| 
      
 80 
     | 
    
         
            +
                end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
              end
         
     | 
| 
      
 83 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module EventMachine
         
     | 
| 
      
 2 
     | 
    
         
            +
              class HttpRequest
         
     | 
| 
      
 3 
     | 
    
         
            +
                 %w[get head post delete put].each do |type|
         
     | 
| 
      
 4 
     | 
    
         
            +
                   class_eval %[
         
     | 
| 
      
 5 
     | 
    
         
            +
                     alias :a#{type} :#{type}
         
     | 
| 
      
 6 
     | 
    
         
            +
                     def #{type}(options = {}, &blk)
         
     | 
| 
      
 7 
     | 
    
         
            +
                       f = Fiber.current
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                        conn = setup_request(:#{type}, options, &blk)
         
     | 
| 
      
 10 
     | 
    
         
            +
                        conn.callback { f.resume(conn) }
         
     | 
| 
      
 11 
     | 
    
         
            +
                        conn.errback  { f.resume(conn) }
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                        Fiber.yield  
         
     | 
| 
      
 14 
     | 
    
         
            +
                     end
         
     | 
| 
      
 15 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 16 
     | 
    
         
            +
                end  
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'em-jack'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # WANT: namespaced under EventMachine.. would be nice :-)
         
     | 
| 
      
 4 
     | 
    
         
            +
            # NOTE: no need for "pooling" since Beanstalk supports pipelining
         
     | 
| 
      
 5 
     | 
    
         
            +
            module EMJack
         
     | 
| 
      
 6 
     | 
    
         
            +
              class Connection
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                alias :ause :use
         
     | 
| 
      
 9 
     | 
    
         
            +
                def use(tube, &blk)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  return if @used_tube == tube
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  f = Fiber.current
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  # WANT: per command errbacks, would be nice, instead of one global
         
     | 
| 
      
 15 
     | 
    
         
            +
                  # errback  = Proc.new {|r| f.resume(r) }
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  on_error {|r| f.resume(r)}
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  @used_tube = tube
         
     | 
| 
      
 20 
     | 
    
         
            +
                  @conn.send(:use, tube)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  
         
     | 
| 
      
 22 
     | 
    
         
            +
                  # WANT: Add conditional on add_deferrable to either accept two procs, or a single block
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #       .. two procs = callback, errback
         
     | 
| 
      
 24 
     | 
    
         
            +
                  add_deferrable { |r| f.resume(r) }
         
     | 
| 
      
 25 
     | 
    
         
            +
                  
         
     | 
| 
      
 26 
     | 
    
         
            +
                  Fiber.yield
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module EventMachine
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Synchrony
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Multi
         
     | 
| 
      
 4 
     | 
    
         
            +
                  include EventMachine::Deferrable
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  attr_reader :requests, :responses
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def initialize
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @requests = []
         
     | 
| 
      
 10 
     | 
    
         
            +
                    @responses = {:callback => {}, :errback => {}}
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  def add(name, conn)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    fiber = Fiber.current
         
     | 
| 
      
 15 
     | 
    
         
            +
                    conn.callback { @responses[:callback][name] = conn; check_progress(fiber) }
         
     | 
| 
      
 16 
     | 
    
         
            +
                    conn.errback  { @responses[:errback][name] = conn;  check_progress(fiber) }
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    @requests.push(conn)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def perform
         
     | 
| 
      
 22 
     | 
    
         
            +
                    Fiber.yield
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  protected
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    def check_progress(fiber)
         
     | 
| 
      
 28 
     | 
    
         
            +
                      if (@responses[:callback].size + @responses[:errback].size) == @requests.size
         
     | 
| 
      
 29 
     | 
    
         
            +
                        succeed
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                        # continue processing
         
     | 
| 
      
 32 
     | 
    
         
            +
                        fiber.resume(self)
         
     | 
| 
      
 33 
     | 
    
         
            +
                      end
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module EventMachine
         
     | 
| 
      
 2 
     | 
    
         
            +
              class MySQL
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                alias :aquery :query
         
     | 
| 
      
 5 
     | 
    
         
            +
                def query(sql, &blk)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  f = Fiber.current
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  # TODO: blk case does not work. Hmm?
         
     | 
| 
      
 9 
     | 
    
         
            +
                  cb = Proc.new { |r| f.resume(r) }
         
     | 
| 
      
 10 
     | 
    
         
            +
                  eb = Proc.new { |r| f.resume(r) }
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  @connection.execute(sql, cb, eb)
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  Fiber.yield
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,67 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "remcached"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Memcached
         
     | 
| 
      
 4 
     | 
    
         
            +
              class << self
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def connect(servers)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  Memcached.servers = servers
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  f = Fiber.current
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @t = EM::PeriodicTimer.new(0.01) do
         
     | 
| 
      
 11 
     | 
    
         
            +
                    if Memcached.usable?
         
     | 
| 
      
 12 
     | 
    
         
            +
                      @t.cancel
         
     | 
| 
      
 13 
     | 
    
         
            +
                      f.resume(self)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    end
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  Fiber.yield
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                %w[add get set delete].each do |type|
         
     | 
| 
      
 21 
     | 
    
         
            +
                  class_eval %[
         
     | 
| 
      
 22 
     | 
    
         
            +
                    def a#{type}(contents, &callback)
         
     | 
| 
      
 23 
     | 
    
         
            +
                      df = EventMachine::DefaultDeferrable.new
         
     | 
| 
      
 24 
     | 
    
         
            +
                      df.callback &callback
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                      cb = Proc.new { |res| df.succeed(res) }
         
     | 
| 
      
 27 
     | 
    
         
            +
                      operation Request::#{type.capitalize}, contents, &cb
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                        df
         
     | 
| 
      
 30 
     | 
    
         
            +
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                    def #{type}(contents, &callback)
         
     | 
| 
      
 33 
     | 
    
         
            +
                      fiber = Fiber.current
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                      df = a#{type}(contents, &Proc.new { |res| fiber.resume(res) })
         
     | 
| 
      
 36 
     | 
    
         
            +
                      df.callback &callback
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                      Fiber.yield
         
     | 
| 
      
 39 
     | 
    
         
            +
                    end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                %w[add get set delete].each do |type|
         
     | 
| 
      
 44 
     | 
    
         
            +
                   class_eval %[
         
     | 
| 
      
 45 
     | 
    
         
            +
                     def amulti_#{type}(contents, &callback)
         
     | 
| 
      
 46 
     | 
    
         
            +
                       df = EventMachine::DefaultDeferrable.new
         
     | 
| 
      
 47 
     | 
    
         
            +
                       df.callback &callback
         
     | 
| 
      
 48 
     | 
    
         
            +
                
         
     | 
| 
      
 49 
     | 
    
         
            +
                       cb = Proc.new { |res| df.succeed(res) }
         
     | 
| 
      
 50 
     | 
    
         
            +
                       multi_operation Request::#{type.capitalize}, contents, &cb
         
     | 
| 
      
 51 
     | 
    
         
            +
                
         
     | 
| 
      
 52 
     | 
    
         
            +
                         df
         
     | 
| 
      
 53 
     | 
    
         
            +
                     end
         
     | 
| 
      
 54 
     | 
    
         
            +
                
         
     | 
| 
      
 55 
     | 
    
         
            +
                     def multi_#{type}(contents, &callback)
         
     | 
| 
      
 56 
     | 
    
         
            +
                       fiber = Fiber.current
         
     | 
| 
      
 57 
     | 
    
         
            +
                
         
     | 
| 
      
 58 
     | 
    
         
            +
                       df = amulti_#{type}(contents, &Proc.new { |res| fiber.resume(res) })
         
     | 
| 
      
 59 
     | 
    
         
            +
                       df.callback &callback
         
     | 
| 
      
 60 
     | 
    
         
            +
                
         
     | 
| 
      
 61 
     | 
    
         
            +
                       Fiber.yield
         
     | 
| 
      
 62 
     | 
    
         
            +
                     end
         
     | 
| 
      
 63 
     | 
    
         
            +
                   ]
         
     | 
| 
      
 64 
     | 
    
         
            +
                 end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,41 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec/helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            DELAY = 0.25
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            describe EMJack do
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              it "should fire sequential Beanstalk requests" do
         
     | 
| 
      
 8 
     | 
    
         
            +
                EventMachine.run do
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  Fiber.new {
         
     | 
| 
      
 11 
     | 
    
         
            +
                    jack = EMJack::Connection.new
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                    r = jack.use('mytube')
         
     | 
| 
      
 14 
     | 
    
         
            +
                    r.should == 'mytube'
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    EventMachine.stop
         
     | 
| 
      
 17 
     | 
    
         
            +
                  }.resume
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              it "should fire multiple requests in parallel" do
         
     | 
| 
      
 22 
     | 
    
         
            +
                EventMachine.run do
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  Fiber.new {
         
     | 
| 
      
 25 
     | 
    
         
            +
                    jack = EMJack::Connection.new
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    multi = EventMachine::Multi.new
         
     | 
| 
      
 28 
     | 
    
         
            +
                    multi.add jack.ause('mytube-1')
         
     | 
| 
      
 29 
     | 
    
         
            +
                    multi.add jack.ause('mytube-2')
         
     | 
| 
      
 30 
     | 
    
         
            +
                    res = multi.perform
         
     | 
| 
      
 31 
     | 
    
         
            +
                    
         
     | 
| 
      
 32 
     | 
    
         
            +
                    res.responses.size.should == 2
         
     | 
| 
      
 33 
     | 
    
         
            +
                    p [:multi, res.responses]
         
     | 
| 
      
 34 
     | 
    
         
            +
                    
         
     | 
| 
      
 35 
     | 
    
         
            +
                    EventMachine.stop
         
     | 
| 
      
 36 
     | 
    
         
            +
                  }.resume
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
              
         
     | 
| 
      
 41 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,129 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "spec/helper/all"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            DELAY = 0.25
         
     | 
| 
      
 4 
     | 
    
         
            +
            QUERY = "select sleep(#{DELAY})"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            describe EventMachine::Synchrony::ConnectionPool do
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              it "should queue requests if pool size is exceeded" do
         
     | 
| 
      
 9 
     | 
    
         
            +
                EventMachine.run do
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  db = EventMachine::Synchrony::ConnectionPool.new(size: 1) do
         
     | 
| 
      
 12 
     | 
    
         
            +
                    EventMachine::MySQL.new(host: "localhost")
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  Fiber.new {
         
     | 
| 
      
 16 
     | 
    
         
            +
                    start = now
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    multi = EventMachine::Synchrony::Multi.new
         
     | 
| 
      
 19 
     | 
    
         
            +
                    multi.add :a, db.aquery(QUERY)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    multi.add :b, db.aquery(QUERY)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    res = multi.perform
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    (now - start.to_f).should be_within(DELAY * 2 * 0.15).of(DELAY * 2)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    res.responses[:callback].size.should == 2
         
     | 
| 
      
 25 
     | 
    
         
            +
                    res.responses[:errback].size.should == 0
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    EventMachine.stop
         
     | 
| 
      
 28 
     | 
    
         
            +
                  }.resume
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              it "should execute multiple async pool requests within same fiber" do
         
     | 
| 
      
 33 
     | 
    
         
            +
                EventMachine.run do
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  db = EventMachine::Synchrony::ConnectionPool.new(size: 2) do
         
     | 
| 
      
 36 
     | 
    
         
            +
                    EventMachine::MySQL.new(host: "localhost")
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  Fiber.new {
         
     | 
| 
      
 40 
     | 
    
         
            +
                    start = now
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    multi = EventMachine::Synchrony::Multi.new
         
     | 
| 
      
 43 
     | 
    
         
            +
                    multi.add :a, db.aquery(QUERY)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    multi.add :b, db.aquery(QUERY)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    res = multi.perform
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                    (now - start.to_f).should be_within(DELAY * 0.15).of(DELAY)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    res.responses[:callback].size.should == 2
         
     | 
| 
      
 49 
     | 
    
         
            +
                    res.responses[:errback].size.should == 0
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                    EventMachine.stop
         
     | 
| 
      
 52 
     | 
    
         
            +
                  }.resume
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
              end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
              it "should share connection pool between different fibers" do
         
     | 
| 
      
 57 
     | 
    
         
            +
                EventMachine.run do
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                  db = EventMachine::Synchrony::ConnectionPool.new(size: 2) do
         
     | 
| 
      
 60 
     | 
    
         
            +
                    EventMachine::MySQL.new(host: "localhost")
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                  Fiber.new {
         
     | 
| 
      
 64 
     | 
    
         
            +
                    start = now
         
     | 
| 
      
 65 
     | 
    
         
            +
                    results = []
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                    fiber = Fiber.current
         
     | 
| 
      
 68 
     | 
    
         
            +
                    2.times do |n|
         
     | 
| 
      
 69 
     | 
    
         
            +
                      Fiber.new {
         
     | 
| 
      
 70 
     | 
    
         
            +
                        results.push db.query(QUERY)
         
     | 
| 
      
 71 
     | 
    
         
            +
                        fiber.transfer if results.size == 2
         
     | 
| 
      
 72 
     | 
    
         
            +
                      }.resume
         
     | 
| 
      
 73 
     | 
    
         
            +
                    end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                    # wait for workers
         
     | 
| 
      
 76 
     | 
    
         
            +
                    Fiber.yield
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                    (now - start.to_f).should be_within(DELAY * 0.15).of(DELAY)
         
     | 
| 
      
 79 
     | 
    
         
            +
                    results.size.should == 2
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                    EventMachine.stop
         
     | 
| 
      
 82 
     | 
    
         
            +
                  }.resume
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
              end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
              it "should share connection pool between different fibers & async requests" do
         
     | 
| 
      
 88 
     | 
    
         
            +
                EventMachine.run do
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                  db = EventMachine::Synchrony::ConnectionPool.new(size: 5) do
         
     | 
| 
      
 91 
     | 
    
         
            +
                    EventMachine::MySQL.new(host: "localhost")
         
     | 
| 
      
 92 
     | 
    
         
            +
                  end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                  Fiber.new {
         
     | 
| 
      
 95 
     | 
    
         
            +
                    start = now
         
     | 
| 
      
 96 
     | 
    
         
            +
                    results = []
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                    fiber = Fiber.current
         
     | 
| 
      
 99 
     | 
    
         
            +
                    2.times do |n|
         
     | 
| 
      
 100 
     | 
    
         
            +
                      Fiber.new {
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                        multi = EventMachine::Synchrony::Multi.new
         
     | 
| 
      
 103 
     | 
    
         
            +
                        multi.add :a, db.aquery(QUERY)
         
     | 
| 
      
 104 
     | 
    
         
            +
                        multi.add :b, db.aquery(QUERY)
         
     | 
| 
      
 105 
     | 
    
         
            +
                        results.push multi.perform
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                        fiber.transfer if results.size == 3
         
     | 
| 
      
 108 
     | 
    
         
            +
                      }.resume
         
     | 
| 
      
 109 
     | 
    
         
            +
                    end
         
     | 
| 
      
 110 
     | 
    
         
            +
                    
         
     | 
| 
      
 111 
     | 
    
         
            +
                    Fiber.new {
         
     | 
| 
      
 112 
     | 
    
         
            +
                      # execute a synchronous requests
         
     | 
| 
      
 113 
     | 
    
         
            +
                      results.push db.query(QUERY)
         
     | 
| 
      
 114 
     | 
    
         
            +
                      fiber.transfer if results.size == 3
         
     | 
| 
      
 115 
     | 
    
         
            +
                    }.resume
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                    # wait for workers
         
     | 
| 
      
 118 
     | 
    
         
            +
                    Fiber.yield
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                    (now - start.to_f).should be_within(DELAY * 0.15).of(DELAY)
         
     | 
| 
      
 121 
     | 
    
         
            +
                    results.size.should == 3
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                    EventMachine.stop
         
     | 
| 
      
 124 
     | 
    
         
            +
                  }.resume
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                end
         
     | 
| 
      
 127 
     | 
    
         
            +
              end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/helper/all.rb
    ADDED
    
    | 
         @@ -0,0 +1,16 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'spec'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'pp'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            require 'em-http'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'em-mysqlplus'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            require 'lib/em-synchrony'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'helper/tolerance_matcher'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'helper/stub-http-server'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            def now(); Time.now.to_f; end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            Spec::Runner.configure do |config|
         
     | 
| 
      
 15 
     | 
    
         
            +
              config.include(Sander6::CustomMatchers)
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class StubServer
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Server
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_accessor :response, :delay
         
     | 
| 
      
 4 
     | 
    
         
            +
                def receive_data(data)
         
     | 
| 
      
 5 
     | 
    
         
            +
                  EM.add_timer(@delay) {
         
     | 
| 
      
 6 
     | 
    
         
            +
                    send_data @response
         
     | 
| 
      
 7 
     | 
    
         
            +
                    close_connection_after_writing
         
     | 
| 
      
 8 
     | 
    
         
            +
                  }
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              def initialize(response, delay = 0, port=8081)
         
     | 
| 
      
 13 
     | 
    
         
            +
                @sig = EventMachine::start_server("127.0.0.1", port, Server) { |s|
         
     | 
| 
      
 14 
     | 
    
         
            +
                  s.response = response
         
     | 
| 
      
 15 
     | 
    
         
            +
                  s.delay = delay
         
     | 
| 
      
 16 
     | 
    
         
            +
                }
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              def stop
         
     | 
| 
      
 20 
     | 
    
         
            +
                EventMachine.stop_server @sig
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # courtesy of sander 6
         
     | 
| 
      
 3 
     | 
    
         
            +
            # - http://github.com/sander6/custom_matchers/blob/master/lib/matchers/tolerance_matchers.rb
         
     | 
| 
      
 4 
     | 
    
         
            +
            #
         
     | 
| 
      
 5 
     | 
    
         
            +
            module Sander6
         
     | 
| 
      
 6 
     | 
    
         
            +
              module CustomMatchers
         
     | 
| 
      
 7 
     | 
    
         
            +
                
         
     | 
| 
      
 8 
     | 
    
         
            +
                class ToleranceMatcher
         
     | 
| 
      
 9 
     | 
    
         
            +
                  def initialize(tolerance)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    @tolerance = tolerance
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @target = 0
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def of(target)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @target = target
         
     | 
| 
      
 16 
     | 
    
         
            +
                    self
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def matches?(value)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @value = value
         
     | 
| 
      
 21 
     | 
    
         
            +
                    ((@target - @tolerance)..(@target + @tolerance)).include?(@value)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def failure_message
         
     | 
| 
      
 25 
     | 
    
         
            +
                    "Expected #{@value.inspect} to be within #{@tolerance.inspect} of #{@target.inspect}, but it wasn't.\n" +
         
     | 
| 
      
 26 
     | 
    
         
            +
                      "Difference: #{@value - @target}"
         
     | 
| 
      
 27 
     | 
    
         
            +
                      end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  def negative_failure_message
         
     | 
| 
      
 30 
     | 
    
         
            +
                    "Expected #{@value.inspect} not to be within #{@tolerance.inspect} of #{@target.inspect}, but it was.\n" +
         
     | 
| 
      
 31 
     | 
    
         
            +
                      "Difference: #{@value - @target}"
         
     | 
| 
      
 32 
     | 
    
         
            +
                      end
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def be_within(value)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  Sander6::CustomMatchers::ToleranceMatcher.new(value)
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/http_spec.rb
    ADDED
    
    | 
         @@ -0,0 +1,51 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "spec/helper/all"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            URL = "http://localhost:8081/"
         
     | 
| 
      
 4 
     | 
    
         
            +
            DELAY = 0.25
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            describe EventMachine::HttpRequest do
         
     | 
| 
      
 7 
     | 
    
         
            +
              it "should fire sequential requests" do
         
     | 
| 
      
 8 
     | 
    
         
            +
                EventMachine.run do
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @s = StubServer.new("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nFoo", DELAY)
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  Fiber.new {
         
     | 
| 
      
 12 
     | 
    
         
            +
                    start = now
         
     | 
| 
      
 13 
     | 
    
         
            +
                    order = []
         
     | 
| 
      
 14 
     | 
    
         
            +
                    order.push :get  if EventMachine::HttpRequest.new(URL).get
         
     | 
| 
      
 15 
     | 
    
         
            +
                    order.push :post if EventMachine::HttpRequest.new(URL).post
         
     | 
| 
      
 16 
     | 
    
         
            +
                    order.push :head if EventMachine::HttpRequest.new(URL).head
         
     | 
| 
      
 17 
     | 
    
         
            +
                    order.push :post if EventMachine::HttpRequest.new(URL).delete
         
     | 
| 
      
 18 
     | 
    
         
            +
                    order.push :put  if EventMachine::HttpRequest.new(URL).put
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    (now - start.to_f).should be_within(DELAY * order.size * 0.15).of(DELAY * order.size)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    order.should == [:get, :post, :head, :post, :put]
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    EventMachine.stop
         
     | 
| 
      
 24 
     | 
    
         
            +
                  }.resume
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              it "should fire simultaneous requests via Multi interface" do
         
     | 
| 
      
 29 
     | 
    
         
            +
                EventMachine.run do
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @s = StubServer.new("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nFoo", DELAY)
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  Fiber.new {
         
     | 
| 
      
 33 
     | 
    
         
            +
                    start = now
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    multi = EventMachine::Synchrony::Multi.new
         
     | 
| 
      
 36 
     | 
    
         
            +
                    multi.add :a, EventMachine::HttpRequest.new(URL).aget
         
     | 
| 
      
 37 
     | 
    
         
            +
                    multi.add :b, EventMachine::HttpRequest.new(URL).apost
         
     | 
| 
      
 38 
     | 
    
         
            +
                    multi.add :c, EventMachine::HttpRequest.new(URL).ahead
         
     | 
| 
      
 39 
     | 
    
         
            +
                    multi.add :d, EventMachine::HttpRequest.new(URL).adelete
         
     | 
| 
      
 40 
     | 
    
         
            +
                    multi.add :e, EventMachine::HttpRequest.new(URL).aput
         
     | 
| 
      
 41 
     | 
    
         
            +
                    res = multi.perform
         
     | 
| 
      
 42 
     | 
    
         
            +
                    
         
     | 
| 
      
 43 
     | 
    
         
            +
                    (now - start.to_f).should be_within(DELAY * 0.15).of(DELAY)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    res.responses[:callback].size.should == 5
         
     | 
| 
      
 45 
     | 
    
         
            +
                    res.responses[:errback].size.should == 0
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                    EventMachine.stop
         
     | 
| 
      
 48 
     | 
    
         
            +
                  }.resume
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/mysql_spec.rb
    ADDED
    
    | 
         @@ -0,0 +1,93 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "spec/helper/all"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "em-mysqlplus"
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            DELAY = 0.25
         
     | 
| 
      
 5 
     | 
    
         
            +
            QUERY = "select sleep(#{DELAY})"
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            describe EventMachine::MySQL do
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              it "should fire sequential, synchronous requests" do
         
     | 
| 
      
 10 
     | 
    
         
            +
                EventMachine.run do
         
     | 
| 
      
 11 
     | 
    
         
            +
                  Fiber.new {
         
     | 
| 
      
 12 
     | 
    
         
            +
                    db = EventMachine::MySQL.new(host: "localhost")
         
     | 
| 
      
 13 
     | 
    
         
            +
                    start = now
         
     | 
| 
      
 14 
     | 
    
         
            +
                    res = []
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    res.push db.query(QUERY)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    res.push db.query(QUERY)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    (now - start.to_f).should be_within(DELAY * res.size * 0.15).of(DELAY * res.size)
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    EventMachine.stop
         
     | 
| 
      
 21 
     | 
    
         
            +
                  }.resume
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              it "should have accept a callback, errback on async queries" do
         
     | 
| 
      
 26 
     | 
    
         
            +
                EventMachine.run do
         
     | 
| 
      
 27 
     | 
    
         
            +
                  db = EventMachine::MySQL.new(host: "localhost")
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  res = db.aquery(QUERY)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  res.errback {|r| fail }
         
     | 
| 
      
 31 
     | 
    
         
            +
                  res.callback {|r|
         
     | 
| 
      
 32 
     | 
    
         
            +
                    r.all_hashes.size.should == 1
         
     | 
| 
      
 33 
     | 
    
         
            +
                    EventMachine.stop
         
     | 
| 
      
 34 
     | 
    
         
            +
                  }
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              it "should fire simultaneous requests via Multi interface" do
         
     | 
| 
      
 39 
     | 
    
         
            +
                EventMachine.run do
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  db = EventMachine::Synchrony::ConnectionPool.new(size: 2) do
         
     | 
| 
      
 42 
     | 
    
         
            +
                    EventMachine::MySQL.new(host: "localhost")
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  Fiber.new {
         
     | 
| 
      
 46 
     | 
    
         
            +
                    start = now
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                    multi = EventMachine::Synchrony::Multi.new
         
     | 
| 
      
 49 
     | 
    
         
            +
                    multi.add :a, db.aquery(QUERY)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    multi.add :b, db.aquery(QUERY)
         
     | 
| 
      
 51 
     | 
    
         
            +
                    res = multi.perform
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                    (now - start.to_f).should be_within(DELAY * 0.15).of(DELAY)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    res.responses[:callback].size.should == 2
         
     | 
| 
      
 55 
     | 
    
         
            +
                    res.responses[:errback].size.should == 0
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                    EventMachine.stop
         
     | 
| 
      
 58 
     | 
    
         
            +
                  }.resume
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
              it "should fire sequential and simultaneous MySQL requests" do
         
     | 
| 
      
 63 
     | 
    
         
            +
                EventMachine.run do
         
     | 
| 
      
 64 
     | 
    
         
            +
                  db = EventMachine::Synchrony::ConnectionPool.new(size: 3) do
         
     | 
| 
      
 65 
     | 
    
         
            +
                    EventMachine::MySQL.new(host: "localhost")
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                  Fiber.new {
         
     | 
| 
      
 69 
     | 
    
         
            +
                    start = now
         
     | 
| 
      
 70 
     | 
    
         
            +
                    res = []
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                    res.push db.query(QUERY)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    res.push db.query(QUERY)
         
     | 
| 
      
 74 
     | 
    
         
            +
                    (now - start.to_f).should be_within(DELAY * res.size * 0.15).of(DELAY * res.size)
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                    start = now
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                    multi = EventMachine::Synchrony::Multi.new
         
     | 
| 
      
 79 
     | 
    
         
            +
                    multi.add :a, db.aquery(QUERY)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    multi.add :b, db.aquery(QUERY)
         
     | 
| 
      
 81 
     | 
    
         
            +
                    multi.add :c, db.aquery(QUERY)
         
     | 
| 
      
 82 
     | 
    
         
            +
                    res = multi.perform
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                    (now - start.to_f).should be_within(DELAY * 0.15).of(DELAY)
         
     | 
| 
      
 85 
     | 
    
         
            +
                    res.responses[:callback].size.should == 3
         
     | 
| 
      
 86 
     | 
    
         
            +
                    res.responses[:errback].size.should == 0
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                    EventMachine.stop
         
     | 
| 
      
 89 
     | 
    
         
            +
                  }.resume
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
              end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,51 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "spec/helper/all"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "remcached"
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            describe Memcached do
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              it "should yield until connection is ready" do
         
     | 
| 
      
 7 
     | 
    
         
            +
                EventMachine.run do
         
     | 
| 
      
 8 
     | 
    
         
            +
                  Fiber.new {
         
     | 
| 
      
 9 
     | 
    
         
            +
                    Memcached.connect %w(localhost)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    Memcached.usable?.should be_true
         
     | 
| 
      
 11 
     | 
    
         
            +
                    EventMachine.stop
         
     | 
| 
      
 12 
     | 
    
         
            +
                  }.resume
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              it "should fire sequential memcached requests" do
         
     | 
| 
      
 17 
     | 
    
         
            +
                EventMachine.run do
         
     | 
| 
      
 18 
     | 
    
         
            +
                  Fiber.new {
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    Memcached.connect %w(localhost)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    Memcached.get(key: 'hai') do |res|
         
     | 
| 
      
 22 
     | 
    
         
            +
                      res[:value].should match('Not found')
         
     | 
| 
      
 23 
     | 
    
         
            +
                    end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    Memcached.set(key: 'hai', value: 'win')
         
     | 
| 
      
 26 
     | 
    
         
            +
                    Memcached.add(key: 'count')
         
     | 
| 
      
 27 
     | 
    
         
            +
                    Memcached.delete(key: 'hai')           
         
     | 
| 
      
 28 
     | 
    
         
            +
                    
         
     | 
| 
      
 29 
     | 
    
         
            +
                    EventMachine.stop
         
     | 
| 
      
 30 
     | 
    
         
            +
                  }.resume
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
              
         
     | 
| 
      
 34 
     | 
    
         
            +
              it "should fire multi memcached requests" do
         
     | 
| 
      
 35 
     | 
    
         
            +
                pending "remcached borked? opened a ticket"
         
     | 
| 
      
 36 
     | 
    
         
            +
                
         
     | 
| 
      
 37 
     | 
    
         
            +
                EventMachine.run do
         
     | 
| 
      
 38 
     | 
    
         
            +
                  Fiber.new {
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                    Memcached.connect %w(localhost)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    
         
     | 
| 
      
 42 
     | 
    
         
            +
                    Memcached.multi_get([{:key => 'foo'},{:key => 'bar'}, {:key => 'test'}]) do |res|
         
     | 
| 
      
 43 
     | 
    
         
            +
                      p res
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
                            
         
     | 
| 
      
 46 
     | 
    
         
            +
                    EventMachine.stop
         
     | 
| 
      
 47 
     | 
    
         
            +
                  }.resume
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,100 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification 
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: em-synchrony
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version 
         
     | 
| 
      
 4 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 5 
     | 
    
         
            +
              segments: 
         
     | 
| 
      
 6 
     | 
    
         
            +
              - 0
         
     | 
| 
      
 7 
     | 
    
         
            +
              - 1
         
     | 
| 
      
 8 
     | 
    
         
            +
              - 1
         
     | 
| 
      
 9 
     | 
    
         
            +
              version: 0.1.1
         
     | 
| 
      
 10 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 11 
     | 
    
         
            +
            authors: 
         
     | 
| 
      
 12 
     | 
    
         
            +
            - Ilya Grigorik
         
     | 
| 
      
 13 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 14 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 15 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            date: 2010-03-18 00:00:00 -04:00
         
     | 
| 
      
 18 
     | 
    
         
            +
            default_executable: 
         
     | 
| 
      
 19 
     | 
    
         
            +
            dependencies: 
         
     | 
| 
      
 20 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 21 
     | 
    
         
            +
              name: eventmachine
         
     | 
| 
      
 22 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 23 
     | 
    
         
            +
              requirement: &id001 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 24 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 25 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 26 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 27 
     | 
    
         
            +
                    segments: 
         
     | 
| 
      
 28 
     | 
    
         
            +
                    - 0
         
     | 
| 
      
 29 
     | 
    
         
            +
                    - 12
         
     | 
| 
      
 30 
     | 
    
         
            +
                    - 9
         
     | 
| 
      
 31 
     | 
    
         
            +
                    version: 0.12.9
         
     | 
| 
      
 32 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 33 
     | 
    
         
            +
              version_requirements: *id001
         
     | 
| 
      
 34 
     | 
    
         
            +
            description: Fiber aware EventMachine libraries
         
     | 
| 
      
 35 
     | 
    
         
            +
            email: ilya@igvita.com
         
     | 
| 
      
 36 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            extra_rdoc_files: 
         
     | 
| 
      
 41 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 42 
     | 
    
         
            +
            files: 
         
     | 
| 
      
 43 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 44 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 45 
     | 
    
         
            +
            - VERSION
         
     | 
| 
      
 46 
     | 
    
         
            +
            - lib/em-synchrony.rb
         
     | 
| 
      
 47 
     | 
    
         
            +
            - lib/em-synchrony/connection_pool.rb
         
     | 
| 
      
 48 
     | 
    
         
            +
            - lib/em-synchrony/em-http.rb
         
     | 
| 
      
 49 
     | 
    
         
            +
            - lib/em-synchrony/em-jack.rb
         
     | 
| 
      
 50 
     | 
    
         
            +
            - lib/em-synchrony/em-multi.rb
         
     | 
| 
      
 51 
     | 
    
         
            +
            - lib/em-synchrony/em-mysql.rb
         
     | 
| 
      
 52 
     | 
    
         
            +
            - lib/em-synchrony/em-remcached.rb
         
     | 
| 
      
 53 
     | 
    
         
            +
            - spec/beanstalk_spec.rb
         
     | 
| 
      
 54 
     | 
    
         
            +
            - spec/connection_pool_spec.rb
         
     | 
| 
      
 55 
     | 
    
         
            +
            - spec/helper/all.rb
         
     | 
| 
      
 56 
     | 
    
         
            +
            - spec/helper/stub-http-server.rb
         
     | 
| 
      
 57 
     | 
    
         
            +
            - spec/helper/tolerance_matcher.rb
         
     | 
| 
      
 58 
     | 
    
         
            +
            - spec/http_spec.rb
         
     | 
| 
      
 59 
     | 
    
         
            +
            - spec/mysql_spec.rb
         
     | 
| 
      
 60 
     | 
    
         
            +
            - spec/remcached_spec.rb
         
     | 
| 
      
 61 
     | 
    
         
            +
            has_rdoc: true
         
     | 
| 
      
 62 
     | 
    
         
            +
            homepage: http://github.com/igrigorik/em-synchrony
         
     | 
| 
      
 63 
     | 
    
         
            +
            licenses: []
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 66 
     | 
    
         
            +
            rdoc_options: 
         
     | 
| 
      
 67 
     | 
    
         
            +
            - --charset=UTF-8
         
     | 
| 
      
 68 
     | 
    
         
            +
            require_paths: 
         
     | 
| 
      
 69 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 70 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 71 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 72 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 73 
     | 
    
         
            +
                - !ruby/object:Gem::Version 
         
     | 
| 
      
 74 
     | 
    
         
            +
                  segments: 
         
     | 
| 
      
 75 
     | 
    
         
            +
                  - 1
         
     | 
| 
      
 76 
     | 
    
         
            +
                  - 9
         
     | 
| 
      
 77 
     | 
    
         
            +
                  version: "1.9"
         
     | 
| 
      
 78 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 79 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 80 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 81 
     | 
    
         
            +
                - !ruby/object:Gem::Version 
         
     | 
| 
      
 82 
     | 
    
         
            +
                  segments: 
         
     | 
| 
      
 83 
     | 
    
         
            +
                  - 0
         
     | 
| 
      
 84 
     | 
    
         
            +
                  version: "0"
         
     | 
| 
      
 85 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
            rubyforge_project: em-synchrony
         
     | 
| 
      
 88 
     | 
    
         
            +
            rubygems_version: 1.3.6
         
     | 
| 
      
 89 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 90 
     | 
    
         
            +
            specification_version: 3
         
     | 
| 
      
 91 
     | 
    
         
            +
            summary: Fiber aware EventMachine libraries
         
     | 
| 
      
 92 
     | 
    
         
            +
            test_files: 
         
     | 
| 
      
 93 
     | 
    
         
            +
            - spec/beanstalk_spec.rb
         
     | 
| 
      
 94 
     | 
    
         
            +
            - spec/connection_pool_spec.rb
         
     | 
| 
      
 95 
     | 
    
         
            +
            - spec/helper/all.rb
         
     | 
| 
      
 96 
     | 
    
         
            +
            - spec/helper/stub-http-server.rb
         
     | 
| 
      
 97 
     | 
    
         
            +
            - spec/helper/tolerance_matcher.rb
         
     | 
| 
      
 98 
     | 
    
         
            +
            - spec/http_spec.rb
         
     | 
| 
      
 99 
     | 
    
         
            +
            - spec/mysql_spec.rb
         
     | 
| 
      
 100 
     | 
    
         
            +
            - spec/remcached_spec.rb
         
     |