einhorn 0.8.2 → 1.0.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.
- checksums.yaml +4 -4
 - data/Changes.md +15 -0
 - data/README.md +7 -38
 - data/einhorn.gemspec +23 -21
 - data/example/pool_worker.rb +2 -2
 - data/example/thin_example +8 -8
 - data/example/time_server +5 -5
 - data/lib/einhorn/client.rb +8 -8
 - data/lib/einhorn/command/interface.rb +92 -98
 - data/lib/einhorn/command.rb +75 -85
 - data/lib/einhorn/compat.rb +7 -7
 - data/lib/einhorn/event/abstract_text_descriptor.rb +32 -36
 - data/lib/einhorn/event/ack_timer.rb +2 -2
 - data/lib/einhorn/event/command_server.rb +7 -9
 - data/lib/einhorn/event/connection.rb +1 -3
 - data/lib/einhorn/event/loop_breaker.rb +2 -1
 - data/lib/einhorn/event/persistent.rb +2 -2
 - data/lib/einhorn/event/timer.rb +4 -4
 - data/lib/einhorn/event.rb +20 -20
 - data/lib/einhorn/prctl.rb +2 -2
 - data/lib/einhorn/prctl_linux.rb +13 -14
 - data/lib/einhorn/safe_yaml.rb +17 -0
 - data/lib/einhorn/version.rb +1 -1
 - data/lib/einhorn/worker.rb +26 -30
 - data/lib/einhorn/worker_pool.rb +9 -9
 - data/lib/einhorn.rb +120 -125
 - metadata +37 -110
 - data/.gitignore +0 -17
 - data/.travis.yml +0 -10
 - data/CONTRIBUTORS +0 -6
 - data/Gemfile +0 -11
 - data/History.txt +0 -4
 - data/README.md.in +0 -94
 - data/Rakefile +0 -27
 - data/test/_lib.rb +0 -12
 - data/test/integration/_lib/fixtures/env_printer/env_printer.rb +0 -26
 - data/test/integration/_lib/fixtures/exit_during_upgrade/exiting_server.rb +0 -23
 - data/test/integration/_lib/fixtures/exit_during_upgrade/upgrade_reexec.rb +0 -6
 - data/test/integration/_lib/fixtures/pdeathsig_printer/pdeathsig_printer.rb +0 -29
 - data/test/integration/_lib/fixtures/signal_timeout/sleepy_server.rb +0 -23
 - data/test/integration/_lib/fixtures/upgrade_project/upgrading_server.rb +0 -24
 - data/test/integration/_lib/helpers/einhorn_helpers.rb +0 -148
 - data/test/integration/_lib/helpers.rb +0 -4
 - data/test/integration/_lib.rb +0 -6
 - data/test/integration/pdeathsig.rb +0 -26
 - data/test/integration/startup.rb +0 -31
 - data/test/integration/upgrading.rb +0 -204
 - data/test/unit/_lib/bad_worker.rb +0 -7
 - data/test/unit/_lib/sleep_worker.rb +0 -5
 - data/test/unit/einhorn/client.rb +0 -88
 - data/test/unit/einhorn/command/interface.rb +0 -49
 - data/test/unit/einhorn/command.rb +0 -135
 - data/test/unit/einhorn/event.rb +0 -89
 - data/test/unit/einhorn/worker_pool.rb +0 -39
 - data/test/unit/einhorn.rb +0 -96
 - /data/{LICENSE → LICENSE.txt} +0 -0
 
    
        data/.travis.yml
    DELETED
    
    
    
        data/CONTRIBUTORS
    DELETED
    
    
    
        data/Gemfile
    DELETED
    
    | 
         @@ -1,11 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # Execute bundler hook if present
         
     | 
| 
       2 
     | 
    
         
            -
            ['~/.', '/etc/'].any? do |file|
         
     | 
| 
       3 
     | 
    
         
            -
             File.lstat(path = File.expand_path(file + 'bundle-gemfile-hook')) rescue next
         
     | 
| 
       4 
     | 
    
         
            -
             eval(File.read(path), binding, path); break true
         
     | 
| 
       5 
     | 
    
         
            -
            end || source('https://rubygems.org/')
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
            # Only needed for examples
         
     | 
| 
       8 
     | 
    
         
            -
            gem 'thin-attach_socket'
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
            # Specify your gem's dependencies in einhorn.gemspec
         
     | 
| 
       11 
     | 
    
         
            -
            gemspec
         
     | 
    
        data/History.txt
    DELETED
    
    
    
        data/README.md.in
    DELETED
    
    | 
         @@ -1,94 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # Einhorn: the language-independent shared socket manager
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            Let's say you have a server process which processes one request at a
         
     | 
| 
       6 
     | 
    
         
            -
            time. Your site is becoming increasingly popular, and this one process
         
     | 
| 
       7 
     | 
    
         
            -
            is no longer able to handle all of your inbound connections. However,
         
     | 
| 
       8 
     | 
    
         
            -
            you notice that your box's load number is low.
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
            So you start thinking about how to handle more requests. You could
         
     | 
| 
       11 
     | 
    
         
            -
            rewrite your server to use threads, but threads are a pain to program
         
     | 
| 
       12 
     | 
    
         
            -
            against (and maybe you're writing in Python or Ruby where you don't
         
     | 
| 
       13 
     | 
    
         
            -
            have true threads anyway). You could rewrite your server to be
         
     | 
| 
       14 
     | 
    
         
            -
            event-driven, but that'd require a ton of effort, and it wouldn't help
         
     | 
| 
       15 
     | 
    
         
            -
            you go beyond one core. So instead, you decide to just run multiple
         
     | 
| 
       16 
     | 
    
         
            -
            copies of your server process.
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
            Enter Einhorn. Einhorn makes it easy to run (and keep alive) multiple
         
     | 
| 
       19 
     | 
    
         
            -
            copies of a single long-lived process. If that process is a server
         
     | 
| 
       20 
     | 
    
         
            -
            listening on some socket, Einhorn will open the socket in the master
         
     | 
| 
       21 
     | 
    
         
            -
            process so that it's shared among the workers.
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
            Einhorn is designed to be compatible with arbitrary languages and
         
     | 
| 
       24 
     | 
    
         
            -
            frameworks, requiring minimal modification of your
         
     | 
| 
       25 
     | 
    
         
            -
            application. Einhorn is simple to configure and run.
         
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
            ## Installation
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
            Install from Rubygems as:
         
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
                $ gem install einhorn
         
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
            Or build from source by:
         
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
                $ gem build einhorn.gemspec
         
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
            And then install the built gem.
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
            [[usage]]
         
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
            ## Contributing
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
            Contributions are definitely welcome. To contribute, just follow the
         
     | 
| 
       44 
     | 
    
         
            -
            usual workflow:
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
            1. Fork Einhorn
         
     | 
| 
       47 
     | 
    
         
            -
            2. Create your feature branch (`git checkout -b my-new-feature`)
         
     | 
| 
       48 
     | 
    
         
            -
            3. Commit your changes (`git commit -am 'Added some feature'`)
         
     | 
| 
       49 
     | 
    
         
            -
            4. Push to the branch (`git push origin my-new-feature`)
         
     | 
| 
       50 
     | 
    
         
            -
            5. Create new Github pull request
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
            ## History
         
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
            Einhorn came about when Stripe was investigating seamless code
         
     | 
| 
       55 
     | 
    
         
            -
            upgrading solutions for our API worker processes. We really liked the
         
     | 
| 
       56 
     | 
    
         
            -
            process model of [Unicorn](http://unicorn.bogomips.org/), but didn't
         
     | 
| 
       57 
     | 
    
         
            -
            want to use its HTTP functionality. So Einhorn was born, providing the
         
     | 
| 
       58 
     | 
    
         
            -
            master process functionality of Unicorn (and similar preforking
         
     | 
| 
       59 
     | 
    
         
            -
            servers) to a wider array of applications.
         
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
            See https://stripe.com/blog/meet-einhorn for more background.
         
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
            Stripe currently uses Einhorn in production for a number of
         
     | 
| 
       64 
     | 
    
         
            -
            services. You can use Conrad Irwin's thin-attach_socket gem along with
         
     | 
| 
       65 
     | 
    
         
            -
            EventMachine-LE to support file-descriptor passing. Check out
         
     | 
| 
       66 
     | 
    
         
            -
            `example/thin_example` for an example of running Thin under Einhorn.
         
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
            ## Compatibility
         
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
            Einhorn runs in Ruby 2.0, 2.1, and 2.2
         
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
            The following libraries ease integration with Einhorn with languages other than
         
     | 
| 
       73 
     | 
    
         
            -
            Ruby:
         
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
            - **[go-einhorn](https://github.com/stripe/go-einhorn)**: Stripe's own library
         
     | 
| 
       76 
     | 
    
         
            -
              for *talking* to an einhorn master (doesn't wrap socket code).
         
     | 
| 
       77 
     | 
    
         
            -
            - **[goji](https://github.com/zenazn/goji/)**: Go (golang) server framework. The
         
     | 
| 
       78 
     | 
    
         
            -
              [`bind`](https://godoc.org/github.com/zenazn/goji/bind) and
         
     | 
| 
       79 
     | 
    
         
            -
              [`graceful`](https://godoc.org/github.com/zenazn/goji/graceful)
         
     | 
| 
       80 
     | 
    
         
            -
              packages provide helpers and HTTP/TCP connection wrappers for Einhorn
         
     | 
| 
       81 
     | 
    
         
            -
              integration.
         
     | 
| 
       82 
     | 
    
         
            -
            - **[github.com/CHH/einhorn](https://github.com/CHH/einhorn)**: PHP library
         
     | 
| 
       83 
     | 
    
         
            -
            - **[thin-attach\_socket](https://github.com/ConradIrwin/thin-attach_socket)**:
         
     | 
| 
       84 
     | 
    
         
            -
              run `thin` behind Einhorn
         
     | 
| 
       85 
     | 
    
         
            -
            - **[baseplate](https://reddit.github.io/baseplate/cli/serve.html)**: a
         
     | 
| 
       86 
     | 
    
         
            -
              collection of Python helpers and libraries, with support for running behind
         
     | 
| 
       87 
     | 
    
         
            -
              Einhorn
         
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
            *NB: this list should not imply any official endorsement or vetting!*
         
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
            ## About
         
     | 
| 
       92 
     | 
    
         
            -
             
     | 
| 
       93 
     | 
    
         
            -
            Einhorn is a project of [Stripe](https://stripe.com), led by [Carl Jackson](https://github.com/zenazn). Feel free to get in touch at
         
     | 
| 
       94 
     | 
    
         
            -
            info@stripe.com.
         
     | 
    
        data/Rakefile
    DELETED
    
    | 
         @@ -1,27 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            #!/usr/bin/env rake
         
     | 
| 
       2 
     | 
    
         
            -
            require 'bundler/gem_tasks'
         
     | 
| 
       3 
     | 
    
         
            -
            require 'rake/testtask'
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            desc 'Rebuild the README with the latest usage from einhorn'
         
     | 
| 
       6 
     | 
    
         
            -
            task :readme do
         
     | 
| 
       7 
     | 
    
         
            -
              Dir.chdir(File.dirname(__FILE__))
         
     | 
| 
       8 
     | 
    
         
            -
              readme = File.read('README.md.in')
         
     | 
| 
       9 
     | 
    
         
            -
              usage = `bin/einhorn -h`
         
     | 
| 
       10 
     | 
    
         
            -
              readme.gsub!('[[usage]]', usage)
         
     | 
| 
       11 
     | 
    
         
            -
              File.open('README.md', 'w') {|f| f.write(readme)}
         
     | 
| 
       12 
     | 
    
         
            -
            end
         
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
            task :default => :test do
         
     | 
| 
       15 
     | 
    
         
            -
            end
         
     | 
| 
       16 
     | 
    
         
            -
            require 'bundler/setup'
         
     | 
| 
       17 
     | 
    
         
            -
            require 'chalk-rake/gem_tasks'
         
     | 
| 
       18 
     | 
    
         
            -
            require 'rake/testtask'
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
            Rake::TestTask.new do |t|
         
     | 
| 
       21 
     | 
    
         
            -
              t.libs = ['lib']
         
     | 
| 
       22 
     | 
    
         
            -
              # t.warning = true
         
     | 
| 
       23 
     | 
    
         
            -
              t.verbose = true
         
     | 
| 
       24 
     | 
    
         
            -
              t.test_files = FileList['test/**/*.rb'].reject do |file|
         
     | 
| 
       25 
     | 
    
         
            -
                file.end_with?('_lib.rb') || file.include?('/_lib/')
         
     | 
| 
       26 
     | 
    
         
            -
              end
         
     | 
| 
       27 
     | 
    
         
            -
            end
         
     | 
    
        data/test/_lib.rb
    DELETED
    
    
| 
         @@ -1,26 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'bundler/setup'
         
     | 
| 
       2 
     | 
    
         
            -
            require 'socket'
         
     | 
| 
       3 
     | 
    
         
            -
            require 'einhorn/worker'
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            def einhorn_main
         
     | 
| 
       6 
     | 
    
         
            -
              $stderr.puts "Worker starting up!"
         
     | 
| 
       7 
     | 
    
         
            -
              serv = Socket.for_fd(ENV['EINHORN_FD_0'].to_i)
         
     | 
| 
       8 
     | 
    
         
            -
              $stderr.puts "Worker has a socket"
         
     | 
| 
       9 
     | 
    
         
            -
              Einhorn::Worker.ack!
         
     | 
| 
       10 
     | 
    
         
            -
              $stderr.puts "Worker sent ack to einhorn"
         
     | 
| 
       11 
     | 
    
         
            -
              $stdout.puts "Environment from #{Process.pid} is: #{ENV.inspect}"
         
     | 
| 
       12 
     | 
    
         
            -
              while true
         
     | 
| 
       13 
     | 
    
         
            -
                s, addrinfo = serv.accept
         
     | 
| 
       14 
     | 
    
         
            -
                $stderr.puts "Worker got a socket!"
         
     | 
| 
       15 
     | 
    
         
            -
                output = ""
         
     | 
| 
       16 
     | 
    
         
            -
                ARGV.each do |variable_to_write|
         
     | 
| 
       17 
     | 
    
         
            -
                  output += ENV[variable_to_write].to_s
         
     | 
| 
       18 
     | 
    
         
            -
                end
         
     | 
| 
       19 
     | 
    
         
            -
                s.write(output)
         
     | 
| 
       20 
     | 
    
         
            -
                s.flush
         
     | 
| 
       21 
     | 
    
         
            -
                s.close
         
     | 
| 
       22 
     | 
    
         
            -
                $stderr.puts "Worker closed its socket"
         
     | 
| 
       23 
     | 
    
         
            -
              end
         
     | 
| 
       24 
     | 
    
         
            -
            end
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
            einhorn_main if $0 == __FILE__
         
     | 
| 
         @@ -1,23 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'bundler/setup'
         
     | 
| 
       2 
     | 
    
         
            -
            require 'socket'
         
     | 
| 
       3 
     | 
    
         
            -
            require 'einhorn/worker'
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            def einhorn_main
         
     | 
| 
       6 
     | 
    
         
            -
              serv = Socket.for_fd(Einhorn::Worker.socket!)
         
     | 
| 
       7 
     | 
    
         
            -
              Einhorn::Worker.ack!
         
     | 
| 
       8 
     | 
    
         
            -
              Einhorn::Worker.ping!("id-1")
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
              Signal.trap('USR2') do
         
     | 
| 
       11 
     | 
    
         
            -
                sleep 3
         
     | 
| 
       12 
     | 
    
         
            -
                exit!
         
     | 
| 
       13 
     | 
    
         
            -
              end
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
              while true
         
     | 
| 
       16 
     | 
    
         
            -
                s, _ = serv.accept
         
     | 
| 
       17 
     | 
    
         
            -
                s.write($$)
         
     | 
| 
       18 
     | 
    
         
            -
                s.flush
         
     | 
| 
       19 
     | 
    
         
            -
                s.close
         
     | 
| 
       20 
     | 
    
         
            -
              end
         
     | 
| 
       21 
     | 
    
         
            -
            end
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
            einhorn_main if $0 == __FILE__
         
     | 
| 
         @@ -1,29 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'bundler/setup'
         
     | 
| 
       2 
     | 
    
         
            -
            require 'socket'
         
     | 
| 
       3 
     | 
    
         
            -
            require 'einhorn/worker'
         
     | 
| 
       4 
     | 
    
         
            -
            require 'einhorn/prctl'
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
            def einhorn_main
         
     | 
| 
       7 
     | 
    
         
            -
              serv = Socket.for_fd(Einhorn::Worker.socket!)
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
              Signal.trap("USR2") { exit }
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
              begin
         
     | 
| 
       12 
     | 
    
         
            -
                output = Einhorn::Prctl.get_pdeathsig
         
     | 
| 
       13 
     | 
    
         
            -
                if output == nil then
         
     | 
| 
       14 
     | 
    
         
            -
                  output = "nil"
         
     | 
| 
       15 
     | 
    
         
            -
                end
         
     | 
| 
       16 
     | 
    
         
            -
              rescue NotImplementedError
         
     | 
| 
       17 
     | 
    
         
            -
                output = "not implemented"
         
     | 
| 
       18 
     | 
    
         
            -
              end
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
              Einhorn::Worker.ack!
         
     | 
| 
       21 
     | 
    
         
            -
              while true
         
     | 
| 
       22 
     | 
    
         
            -
                s, _ = serv.accept
         
     | 
| 
       23 
     | 
    
         
            -
                s.write(output)
         
     | 
| 
       24 
     | 
    
         
            -
                s.flush
         
     | 
| 
       25 
     | 
    
         
            -
                s.close
         
     | 
| 
       26 
     | 
    
         
            -
              end
         
     | 
| 
       27 
     | 
    
         
            -
            end
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
            einhorn_main if $0 == __FILE__
         
     | 
| 
         @@ -1,23 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'bundler/setup'
         
     | 
| 
       2 
     | 
    
         
            -
            require 'socket'
         
     | 
| 
       3 
     | 
    
         
            -
            require 'einhorn/worker'
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            def einhorn_main
         
     | 
| 
       6 
     | 
    
         
            -
              serv = Socket.for_fd(Einhorn::Worker.socket!)
         
     | 
| 
       7 
     | 
    
         
            -
              Einhorn::Worker.ack!
         
     | 
| 
       8 
     | 
    
         
            -
              Einhorn::Worker.ping!("id-1")
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
              Signal.trap('USR2') do
         
     | 
| 
       11 
     | 
    
         
            -
                sleep ENV.fetch("TRAP_SLEEP").to_i
         
     | 
| 
       12 
     | 
    
         
            -
                exit
         
     | 
| 
       13 
     | 
    
         
            -
              end
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
              while true
         
     | 
| 
       16 
     | 
    
         
            -
                s, _ = serv.accept
         
     | 
| 
       17 
     | 
    
         
            -
                s.write($$)
         
     | 
| 
       18 
     | 
    
         
            -
                s.flush
         
     | 
| 
       19 
     | 
    
         
            -
                s.close
         
     | 
| 
       20 
     | 
    
         
            -
              end
         
     | 
| 
       21 
     | 
    
         
            -
            end
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
            einhorn_main if $0 == __FILE__
         
     | 
| 
         @@ -1,24 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'bundler/setup'
         
     | 
| 
       2 
     | 
    
         
            -
            require 'socket'
         
     | 
| 
       3 
     | 
    
         
            -
            require 'einhorn/worker'
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            def einhorn_main
         
     | 
| 
       6 
     | 
    
         
            -
              version = File.read(File.join(File.dirname(__FILE__), "version"))
         
     | 
| 
       7 
     | 
    
         
            -
              $stderr.puts "Worker starting up!"
         
     | 
| 
       8 
     | 
    
         
            -
              serv = Socket.for_fd(ENV['EINHORN_FD_0'].to_i)
         
     | 
| 
       9 
     | 
    
         
            -
              $stderr.puts "Worker has a socket"
         
     | 
| 
       10 
     | 
    
         
            -
              Einhorn::Worker.ack!
         
     | 
| 
       11 
     | 
    
         
            -
              $stderr.puts "Worker sent ack to einhorn"
         
     | 
| 
       12 
     | 
    
         
            -
              Einhorn::Worker.ping!("id-1")
         
     | 
| 
       13 
     | 
    
         
            -
              $stderr.puts "Worker has sent a ping to einhorn"
         
     | 
| 
       14 
     | 
    
         
            -
              while true
         
     | 
| 
       15 
     | 
    
         
            -
                s, addrinfo = serv.accept
         
     | 
| 
       16 
     | 
    
         
            -
                $stderr.puts "Worker got a socket!"
         
     | 
| 
       17 
     | 
    
         
            -
                s.write(version)
         
     | 
| 
       18 
     | 
    
         
            -
                s.flush
         
     | 
| 
       19 
     | 
    
         
            -
                s.close
         
     | 
| 
       20 
     | 
    
         
            -
                $stderr.puts "Worker closed its socket"
         
     | 
| 
       21 
     | 
    
         
            -
              end
         
     | 
| 
       22 
     | 
    
         
            -
            end
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
            einhorn_main if $0 == __FILE__
         
     | 
| 
         @@ -1,148 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'subprocess'
         
     | 
| 
       2 
     | 
    
         
            -
            require 'timeout'
         
     | 
| 
       3 
     | 
    
         
            -
            require 'tmpdir'
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            module Helpers
         
     | 
| 
       6 
     | 
    
         
            -
              module EinhornHelpers
         
     | 
| 
       7 
     | 
    
         
            -
                def einhorn_code_dir
         
     | 
| 
       8 
     | 
    
         
            -
                  File.expand_path('../../../../', File.dirname(__FILE__))
         
     | 
| 
       9 
     | 
    
         
            -
                end
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
                def default_einhorn_command
         
     | 
| 
       12 
     | 
    
         
            -
                  cmd = ['bundle', 'exec']
         
     | 
| 
       13 
     | 
    
         
            -
                  cmd << '--keep-file-descriptors' if RUBY_VERSION >= '2.0'
         
     | 
| 
       14 
     | 
    
         
            -
                  cmd << File.expand_path('bin/einhorn', einhorn_code_dir)
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
                  cmd
         
     | 
| 
       17 
     | 
    
         
            -
                end
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
                def with_running_einhorn(cmdline, options = {})
         
     | 
| 
       20 
     | 
    
         
            -
                  options = options.dup
         
     | 
| 
       21 
     | 
    
         
            -
                  einhorn_command = options.delete(:einhorn_command) { default_einhorn_command }
         
     | 
| 
       22 
     | 
    
         
            -
                  expected_exit_code = options.delete(:expected_exit_code) { nil }
         
     | 
| 
       23 
     | 
    
         
            -
                  output_callback = options.delete(:output_callback) { nil }
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
                  stdout, stderr = "", ""
         
     | 
| 
       26 
     | 
    
         
            -
                  communicator = nil
         
     | 
| 
       27 
     | 
    
         
            -
                  process = Bundler.with_clean_env do
         
     | 
| 
       28 
     | 
    
         
            -
                    default_options = {
         
     | 
| 
       29 
     | 
    
         
            -
                      :stdout => Subprocess::PIPE,
         
     | 
| 
       30 
     | 
    
         
            -
                      :stderr => Subprocess::PIPE,
         
     | 
| 
       31 
     | 
    
         
            -
                      :stdin => '/dev/null',
         
     | 
| 
       32 
     | 
    
         
            -
                      :cwd => einhorn_code_dir
         
     | 
| 
       33 
     | 
    
         
            -
                    }
         
     | 
| 
       34 
     | 
    
         
            -
                    Subprocess::Process.new(Array(einhorn_command) + cmdline, default_options.merge(options))
         
     | 
| 
       35 
     | 
    
         
            -
                  end
         
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
                  status = nil
         
     | 
| 
       38 
     | 
    
         
            -
                  begin
         
     | 
| 
       39 
     | 
    
         
            -
                    communicator = Thread.new do
         
     | 
| 
       40 
     | 
    
         
            -
                      begin
         
     | 
| 
       41 
     | 
    
         
            -
                        stdout, stderr = process.communicate
         
     | 
| 
       42 
     | 
    
         
            -
                      rescue Errno::ECHILD
         
     | 
| 
       43 
     | 
    
         
            -
                        # It's dead, and we're not getting anything. This is peaceful.
         
     | 
| 
       44 
     | 
    
         
            -
                      end
         
     | 
| 
       45 
     | 
    
         
            -
                    end
         
     | 
| 
       46 
     | 
    
         
            -
                    yield(process) if block_given?
         
     | 
| 
       47 
     | 
    
         
            -
                  rescue
         
     | 
| 
       48 
     | 
    
         
            -
                    unless (status = process.poll) && status.exited?
         
     | 
| 
       49 
     | 
    
         
            -
                      process.terminate
         
     | 
| 
       50 
     | 
    
         
            -
                    end
         
     | 
| 
       51 
     | 
    
         
            -
                    raise
         
     | 
| 
       52 
     | 
    
         
            -
                  ensure
         
     | 
| 
       53 
     | 
    
         
            -
                    unless (status = process.poll) && status.exited?
         
     | 
| 
       54 
     | 
    
         
            -
                      for i in 1..10 do
         
     | 
| 
       55 
     | 
    
         
            -
                        status = process.poll
         
     | 
| 
       56 
     | 
    
         
            -
                        if status && status.exited?
         
     | 
| 
       57 
     | 
    
         
            -
                          break
         
     | 
| 
       58 
     | 
    
         
            -
                        end
         
     | 
| 
       59 
     | 
    
         
            -
                        sleep(1)
         
     | 
| 
       60 
     | 
    
         
            -
                      end
         
     | 
| 
       61 
     | 
    
         
            -
                      unless status && status.exited?
         
     | 
| 
       62 
     | 
    
         
            -
                        $stderr.puts "Could not get Einhorn to quit within 10 seconds, killing it forcefully..."
         
     | 
| 
       63 
     | 
    
         
            -
                        process.send_signal("KILL")
         
     | 
| 
       64 
     | 
    
         
            -
                        status = process.wait
         
     | 
| 
       65 
     | 
    
         
            -
                      end
         
     | 
| 
       66 
     | 
    
         
            -
                    end
         
     | 
| 
       67 
     | 
    
         
            -
                    communicator.join
         
     | 
| 
       68 
     | 
    
         
            -
                    output_callback.call(stdout, stderr) if output_callback
         
     | 
| 
       69 
     | 
    
         
            -
                  end
         
     | 
| 
       70 
     | 
    
         
            -
                end
         
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
                def einhornsh(commandline, options = {})
         
     | 
| 
       73 
     | 
    
         
            -
                  Subprocess.check_call(%W{bundle exec #{File.expand_path('bin/einhornsh')}} + commandline,
         
     | 
| 
       74 
     | 
    
         
            -
                                        {
         
     | 
| 
       75 
     | 
    
         
            -
                                          :stdin => '/dev/null',
         
     | 
| 
       76 
     | 
    
         
            -
                                          :stdout => '/dev/null',
         
     | 
| 
       77 
     | 
    
         
            -
                                          :stderr => '/dev/null'
         
     | 
| 
       78 
     | 
    
         
            -
                                        }.merge(options))
         
     | 
| 
       79 
     | 
    
         
            -
                end
         
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
                def fixture_path(name)
         
     | 
| 
       82 
     | 
    
         
            -
                  File.expand_path(File.join('../fixtures', name), File.dirname(__FILE__))
         
     | 
| 
       83 
     | 
    
         
            -
                end
         
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
                # Creates a new temporary directory with the initial contents from
         
     | 
| 
       86 
     | 
    
         
            -
                # test/integration/_lib/fixtures/{name} and returns the path to
         
     | 
| 
       87 
     | 
    
         
            -
                # it.  The contents of this directory are temporary and can be
         
     | 
| 
       88 
     | 
    
         
            -
                # safely overwritten.
         
     | 
| 
       89 
     | 
    
         
            -
                def prepare_fixture_directory(name)
         
     | 
| 
       90 
     | 
    
         
            -
                  @fixtured_dirs ||= Set.new
         
     | 
| 
       91 
     | 
    
         
            -
                  new_dir = Dir.mktmpdir(name)
         
     | 
| 
       92 
     | 
    
         
            -
                  @fixtured_dirs << new_dir
         
     | 
| 
       93 
     | 
    
         
            -
                  FileUtils.cp_r(File.join(fixture_path(name), '.'), new_dir, :preserve => true)
         
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
                  new_dir
         
     | 
| 
       96 
     | 
    
         
            -
                end
         
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
                def cleanup_fixtured_directories
         
     | 
| 
       99 
     | 
    
         
            -
                  (@fixtured_dirs || []).each { |dir| FileUtils.rm_rf(dir) }
         
     | 
| 
       100 
     | 
    
         
            -
                end
         
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
                def find_free_port(host='127.0.0.1')
         
     | 
| 
       103 
     | 
    
         
            -
                  open_port = TCPServer.new(host, 0)
         
     | 
| 
       104 
     | 
    
         
            -
                  open_port.addr[1]
         
     | 
| 
       105 
     | 
    
         
            -
                ensure
         
     | 
| 
       106 
     | 
    
         
            -
                  open_port.close
         
     | 
| 
       107 
     | 
    
         
            -
                end
         
     | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
       109 
     | 
    
         
            -
                def get_state(client)
         
     | 
| 
       110 
     | 
    
         
            -
                  client.send_command('command' => 'state')
         
     | 
| 
       111 
     | 
    
         
            -
                  YAML.load(client.receive_message['message'])[:state]
         
     | 
| 
       112 
     | 
    
         
            -
                end
         
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
                def wait_for_open_port
         
     | 
| 
       115 
     | 
    
         
            -
                  max_retries = 50
         
     | 
| 
       116 
     | 
    
         
            -
                  begin
         
     | 
| 
       117 
     | 
    
         
            -
                    read_from_port
         
     | 
| 
       118 
     | 
    
         
            -
                  rescue Errno::ECONNREFUSED
         
     | 
| 
       119 
     | 
    
         
            -
                    max_retries -= 1
         
     | 
| 
       120 
     | 
    
         
            -
                    if max_retries <= 0
         
     | 
| 
       121 
     | 
    
         
            -
                      raise
         
     | 
| 
       122 
     | 
    
         
            -
                    else
         
     | 
| 
       123 
     | 
    
         
            -
                      sleep 0.1
         
     | 
| 
       124 
     | 
    
         
            -
                      retry
         
     | 
| 
       125 
     | 
    
         
            -
                    end
         
     | 
| 
       126 
     | 
    
         
            -
                  end
         
     | 
| 
       127 
     | 
    
         
            -
                end
         
     | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
       129 
     | 
    
         
            -
             
     | 
| 
       130 
     | 
    
         
            -
                def read_from_port
         
     | 
| 
       131 
     | 
    
         
            -
                  ewouldblock = RUBY_VERSION >= '1.9.0' ? IO::WaitWritable : Errno::EINPROGRESS
         
     | 
| 
       132 
     | 
    
         
            -
                  socket = Socket.new(Socket::PF_INET, Socket::SOCK_STREAM, 0)
         
     | 
| 
       133 
     | 
    
         
            -
                  sockaddr = Socket.pack_sockaddr_in(@port, '127.0.0.1')
         
     | 
| 
       134 
     | 
    
         
            -
                  begin
         
     | 
| 
       135 
     | 
    
         
            -
                    socket.connect_nonblock(sockaddr)
         
     | 
| 
       136 
     | 
    
         
            -
                  rescue ewouldblock
         
     | 
| 
       137 
     | 
    
         
            -
                    IO.select(nil, [socket], [], 5)
         
     | 
| 
       138 
     | 
    
         
            -
                    begin
         
     | 
| 
       139 
     | 
    
         
            -
                      socket.connect_nonblock(sockaddr)
         
     | 
| 
       140 
     | 
    
         
            -
                    rescue Errno::EISCONN
         
     | 
| 
       141 
     | 
    
         
            -
                    end
         
     | 
| 
       142 
     | 
    
         
            -
                  end
         
     | 
| 
       143 
     | 
    
         
            -
                  socket.read.chomp
         
     | 
| 
       144 
     | 
    
         
            -
                ensure
         
     | 
| 
       145 
     | 
    
         
            -
                  socket.close if socket
         
     | 
| 
       146 
     | 
    
         
            -
                end
         
     | 
| 
       147 
     | 
    
         
            -
              end
         
     | 
| 
       148 
     | 
    
         
            -
            end
         
     | 
    
        data/test/integration/_lib.rb
    DELETED
    
    
| 
         @@ -1,26 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require(File.expand_path('_lib', File.dirname(__FILE__)))
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            class PdeathsigTest < EinhornIntegrationTestCase
         
     | 
| 
       4 
     | 
    
         
            -
              include Helpers::EinhornHelpers
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
              describe 'when run with -k' do
         
     | 
| 
       7 
     | 
    
         
            -
                before do
         
     | 
| 
       8 
     | 
    
         
            -
                  @dir = prepare_fixture_directory('pdeathsig_printer')
         
     | 
| 
       9 
     | 
    
         
            -
                  @port = find_free_port
         
     | 
| 
       10 
     | 
    
         
            -
                  @server_program = File.join(@dir, 'pdeathsig_printer.rb')
         
     | 
| 
       11 
     | 
    
         
            -
                  @socket_path = File.join(@dir, 'einhorn.sock')
         
     | 
| 
       12 
     | 
    
         
            -
                end
         
     | 
| 
       13 
     | 
    
         
            -
                after { cleanup_fixtured_directories }
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
                it 'sets pdeathsig to USR2 in the child process' do
         
     | 
| 
       16 
     | 
    
         
            -
                  with_running_einhorn(%W{einhorn -m manual -b 127.0.0.1:#{@port} -d #{@socket_path} -k -- ruby #{@server_program}}) do |process|
         
     | 
| 
       17 
     | 
    
         
            -
                    wait_for_open_port
         
     | 
| 
       18 
     | 
    
         
            -
                    output = read_from_port
         
     | 
| 
       19 
     | 
    
         
            -
                    if output != "not implemented" then
         
     | 
| 
       20 
     | 
    
         
            -
                      assert_equal("USR2", output)
         
     | 
| 
       21 
     | 
    
         
            -
                    end
         
     | 
| 
       22 
     | 
    
         
            -
                    process.terminate
         
     | 
| 
       23 
     | 
    
         
            -
                  end
         
     | 
| 
       24 
     | 
    
         
            -
                end
         
     | 
| 
       25 
     | 
    
         
            -
              end
         
     | 
| 
       26 
     | 
    
         
            -
            end
         
     | 
    
        data/test/integration/startup.rb
    DELETED
    
    | 
         @@ -1,31 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require(File.expand_path('_lib', File.dirname(__FILE__)))
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            class StartupTest < EinhornIntegrationTestCase
         
     | 
| 
       4 
     | 
    
         
            -
              include Helpers::EinhornHelpers
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
              describe 'when invoked without args' do
         
     | 
| 
       7 
     | 
    
         
            -
                it 'prints usage and exits with 1' do
         
     | 
| 
       8 
     | 
    
         
            -
                  assert_raises(Subprocess::NonZeroExit) do
         
     | 
| 
       9 
     | 
    
         
            -
                    Subprocess.check_call(default_einhorn_command,
         
     | 
| 
       10 
     | 
    
         
            -
                                          :stdout => Subprocess::PIPE,
         
     | 
| 
       11 
     | 
    
         
            -
                                          :stderr => Subprocess::PIPE) do |einhorn|
         
     | 
| 
       12 
     | 
    
         
            -
                      stdout, stderr = einhorn.communicate
         
     | 
| 
       13 
     | 
    
         
            -
                      assert_match(/\A## Usage/, stdout)
         
     | 
| 
       14 
     | 
    
         
            -
                      assert_equal(1, einhorn.wait.exitstatus)
         
     | 
| 
       15 
     | 
    
         
            -
                    end
         
     | 
| 
       16 
     | 
    
         
            -
                  end
         
     | 
| 
       17 
     | 
    
         
            -
                end
         
     | 
| 
       18 
     | 
    
         
            -
              end
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
              describe 'when invoked with --upgrade-check' do
         
     | 
| 
       21 
     | 
    
         
            -
                it 'successfully exits' do
         
     | 
| 
       22 
     | 
    
         
            -
                  Subprocess.check_call(default_einhorn_command + %w[--upgrade-check],
         
     | 
| 
       23 
     | 
    
         
            -
                                        :stdout => Subprocess::PIPE,
         
     | 
| 
       24 
     | 
    
         
            -
                                        :stderr => Subprocess::PIPE) do |einhorn|
         
     | 
| 
       25 
     | 
    
         
            -
                    stdout, stderr = einhorn.communicate
         
     | 
| 
       26 
     | 
    
         
            -
                    status = einhorn.wait
         
     | 
| 
       27 
     | 
    
         
            -
                    assert_equal(0, status.exitstatus)
         
     | 
| 
       28 
     | 
    
         
            -
                  end
         
     | 
| 
       29 
     | 
    
         
            -
                end
         
     | 
| 
       30 
     | 
    
         
            -
              end
         
     | 
| 
       31 
     | 
    
         
            -
            end
         
     |