uc 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5a3884c1ef367b6d4e8a60f72d8b50a27060e41d
4
+ data.tar.gz: bf05917d1e72924de65d6ec0fddc720cdbfc5ae4
5
+ SHA512:
6
+ metadata.gz: 4f120d3edaf991f4a799fa4130d76c7df56f7f3406e17c0155be8775f9c2fd78b34e606efa00b44f003bb1f1f83519f008542373bb9d78dae6da49d93a93ffeb
7
+ data.tar.gz: 538bf7be85f3052d4ad570aa65124e7e5c9d4b8092caf1a6263df6a03a6c79b084c62b2ff1a1118e19bad1b935fdea3cc47f0e726a85e8934cf0bd41c1893251
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in uc.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Neeraj
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Uc
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'uc'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install uc
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( http://github.com/<my-github-username>/uc/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/uc ADDED
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
3
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
4
+
5
+ require 'optparse'
6
+ require 'uc/error'
7
+ require 'uc/server'
8
+
9
+ options = {}
10
+ opts_parser = OptionParser.new do |opts|
11
+
12
+ banner = []
13
+ banner << "Usage: uc [options] command"
14
+ banner << "Available commands: "
15
+ banner << " start stop restart status "
16
+ banner << " rolling-restart "
17
+
18
+ opts.banner = banner
19
+
20
+ opts.on("-d", "--app-dir [APP DIR]" , "Set app dir") do |d|
21
+ path = Pathname.new(d)
22
+ raise ::Uc::Error, "app_dir path must be absolute" if path.relative?
23
+ options[:app_dir] = path
24
+ end
25
+
26
+ opts.on_tail("-h", "--help", "Show this message") do
27
+ puts opts
28
+ end
29
+ end
30
+
31
+ begin
32
+ opts_parser.parse!(ARGV)
33
+
34
+ app_dir = options[:app_dir] || Dir.pwd
35
+ server = ::Uc::Server.new(app_dir)
36
+ command = ARGV.shift
37
+
38
+ case command
39
+ when "start", "stop", "restart", "status"
40
+ server.send command.to_sym
41
+ when "rr", "rolling-restart"
42
+ server.rolling_restart ARGV.shift
43
+ else
44
+ puts "Invalid command"
45
+ abort
46
+ end
47
+
48
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument, ::Uc::Error => e
49
+ puts "ERROR #{e.message}"
50
+ abort
51
+ end
data/lib/uc/error.rb ADDED
@@ -0,0 +1,4 @@
1
+ module Uc
2
+ class Error < StandardError
3
+ end
4
+ end
data/lib/uc/logger.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'logger'
2
+ module Uc
3
+ module Logger
4
+
5
+ def self.logger
6
+ @logger ||= begin
7
+ logger = ::Logger.new(STDOUT)
8
+ logger.formatter = proc do |severity, datetime, progname, msg|
9
+ "#{msg}\n"
10
+ end
11
+ logger.level = ::Logger::INFO
12
+ logger
13
+ end
14
+ end
15
+
16
+ def logger
17
+ ::Uc::Logger.logger
18
+ end
19
+
20
+ end
21
+ end
data/lib/uc/mqueue.rb ADDED
@@ -0,0 +1,70 @@
1
+ require 'posix_mq'
2
+ require 'uc/logger'
3
+ module Uc
4
+ class Mqueue
5
+ include ::Uc::Logger
6
+
7
+ attr_reader :name
8
+
9
+ def initialize(name)
10
+ @name = name
11
+ end
12
+
13
+ def setup
14
+ attr = ::POSIX_MQ::Attr.new(0,100,100) # o_readonly, maxmsg, msgsize
15
+ puts name
16
+ ::POSIX_MQ.new("/#{name}", :rw, 0700, attr)
17
+ make_empty
18
+ end
19
+
20
+ def reader
21
+ @reader ||= ::POSIX_MQ.new("/#{name}", :r)
22
+ end
23
+
24
+ def nb_reader
25
+ mq = ::POSIX_MQ.new("/#{name}", :r)
26
+ mq.nonblock = true
27
+ return mq
28
+ end
29
+
30
+ def writer
31
+ POSIX_MQ.new("/#{name}", IO::WRONLY)
32
+ end
33
+
34
+ def nb_writer
35
+ writer = POSIX_MQ.new("/#{name}", IO::WRONLY)
36
+ writer.nonblock = true
37
+ return writer
38
+ end
39
+
40
+ def watch(loglevel: :info, msg: "success", err_msg: "error", &block)
41
+ setup
42
+ make_empty
43
+ yield
44
+ wait_for_fin(msg, err_msg, loglevel)
45
+ end
46
+
47
+ def wait_for_fin(msg, err_msg, loglevel)
48
+ message = ""
49
+ timeout = 30
50
+ while message != "fin"
51
+ reader.receive(message, timeout)
52
+ logger.send(loglevel, message) if message != "fin"
53
+ end
54
+ logger.info msg
55
+ rescue Errno::ETIMEDOUT
56
+ logger.info "#{timeout}s timeout reached while waiting for message"
57
+ raise ::Uc::Error, err_msg
58
+ end
59
+
60
+ def make_empty
61
+ mq = nb_reader
62
+ while true do
63
+ mq.receive
64
+ end
65
+ rescue Errno::EAGAIN
66
+ return
67
+ end
68
+
69
+ end
70
+ end
data/lib/uc/server.rb ADDED
@@ -0,0 +1,114 @@
1
+ require 'uc/logger'
2
+ require 'uc/shell_helper'
3
+ require 'uc/mqueue'
4
+ require 'uc/unicorn'
5
+ require 'uc/unicorn_config'
6
+ require 'uc/error'
7
+
8
+ module Uc
9
+ class Server
10
+
11
+ include ::Uc::ShellHelper
12
+ include ::Uc::Logger
13
+
14
+ attr_reader :uconfig
15
+
16
+ def initialize(app_dir)
17
+ @uconfig = ::Uc::UnicornConfig.new(app_dir)
18
+ end
19
+
20
+ def app_env(&block)
21
+ uconfig.dirs_checked? || uconfig.check_dirs
22
+ yield if block
23
+ end
24
+
25
+ def start
26
+ app_env do
27
+ if server_running?
28
+ logger.info "unicorn already running pid #{pid}"
29
+ return
30
+ end
31
+
32
+ cmd %{unicorn -c #{uconfig.config_path} -D}, return_output: false,
33
+ error_msg: "error starting unicorn"
34
+ end
35
+ end
36
+
37
+ def stop
38
+ app_env do
39
+ if not server_running?
40
+ puts "unicorn not running"
41
+ return
42
+ end
43
+
44
+ kill(pid, 30)
45
+ end
46
+ end
47
+
48
+ def kill(pid, timeout)
49
+ Process.kill(:TERM, pid)
50
+ logger.debug "TERM signal sent to #{pid}"
51
+ (1..timeout).each do
52
+ if not process_running? pid
53
+ logger.info "Stopped #{pid}"
54
+ return
55
+ end
56
+ sleep 1
57
+ end
58
+ Process.kill(9, pid)
59
+ sleep 1
60
+ logger.info "Killed #{pid}"
61
+ end
62
+
63
+ def status
64
+ status = ( server_running? ? "Running pid #{pid}" : "Stopped")
65
+ puts status
66
+ end
67
+
68
+ def restart
69
+ stop
70
+ start
71
+ end
72
+
73
+ def rolling_restart(queue = nil)
74
+ app_env
75
+ if not server_running?
76
+ start
77
+ return
78
+ end
79
+ queue ||= get_queue_name
80
+ raise ::Uc::Error, "argument missing mq name" if (queue.nil? || queue.empty?)
81
+ mq = ::Uc::Mqueue.new(queue)
82
+ mq.watch err_msg: "server may not have restarted successfully" do
83
+ Process.kill("USR2", pid)
84
+ end
85
+ end
86
+
87
+ def process_running?(pid)
88
+ return false if pid <= 0
89
+ Process.getpgid pid
90
+ return true
91
+ rescue Errno::ESRCH
92
+ return false
93
+ end
94
+
95
+ def server_running?
96
+ process_running? pid
97
+ end
98
+
99
+ def get_queue_name
100
+ Dir.chdir uconfig.app_dir do
101
+ return ::Uc::Unicorn.get_queue_name
102
+ end
103
+ end
104
+
105
+ def read_pid
106
+ uconfig.read_pid
107
+ end
108
+
109
+ def pid
110
+ @pid ||= read_pid
111
+ end
112
+
113
+ end
114
+ end
@@ -0,0 +1,19 @@
1
+ module Uc
2
+ module ShellHelper
3
+
4
+ def cmd(command, error_msg: nil, return_output: false)
5
+ puts "Running #{command}"
6
+ if return_output
7
+ output = `#{command}`
8
+ else
9
+ output = ""
10
+ system "#{command} 2>&1"
11
+ end
12
+ return_value = $?.exitstatus
13
+ error_msg ||= "Non zero exit for \"#{command}\""
14
+ raise ::Uc::Error, error_msg if return_value !=0
15
+ return output
16
+ end
17
+
18
+ end
19
+ end
data/lib/uc/unicorn.rb ADDED
@@ -0,0 +1,56 @@
1
+ require 'uc/mqueue'
2
+ module Uc
3
+ module Unicorn
4
+
5
+ def self.queue_file
6
+ "config/unicorn_mq"
7
+ end
8
+
9
+ def self.rolling_restart(server, worker, queue_name: nil, sleep_secs: 1)
10
+ queue_name ||= get_queue_name
11
+ old_pid = "#{server.config[:pid]}.oldbin"
12
+ if old_pid != server.pid
13
+ begin
14
+ sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
15
+ Process.kill(sig, File.read(old_pid).to_i)
16
+
17
+ mq = ::Uc::Mqueue.new(queue_name)
18
+ writer = mq.nb_writer
19
+ writer.send("started worker #{worker.nr + 1}")
20
+ if sig == :QUIT
21
+ writer.send("fin")
22
+ end
23
+ sleep sleep_secs
24
+ rescue Errno::ENOENT, Errno::ESRCH, Errno::EAGAIN => e
25
+ end
26
+ end
27
+ end
28
+
29
+ def self.clean_env
30
+ ENV.delete "BUNDLE_BIN_PATH"
31
+ ENV.delete "RUBYLIB"
32
+ ENV.delete "RUBYOPT"
33
+ ENV.delete "GEM_HOME"
34
+ ENV.delete "GEM_PATH"
35
+ end
36
+
37
+
38
+ def self.get_queue_name
39
+ queue_name = queue_name_from_file
40
+ queue_name ||= "unicorn_#{Process.uid}"
41
+ return queue_name
42
+ end
43
+
44
+ def self.queue_name_from_file
45
+ queue_file = Pathname.new self.queue_file
46
+ queue_name = nil
47
+ if queue_file.readable?
48
+ queue_name = File.read(queue_file).chomp
49
+ queue_name = (queue_name.empty? ? nil : queue_name)
50
+ end
51
+ return queue_name
52
+ end
53
+
54
+
55
+ end
56
+ end
data/lib/uc/version.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Uc
2
+ VERSION = "0.0.1"
3
+ end
data/lib/uc.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "uc/version"
2
+
3
+ module Uc
4
+ # Your code goes here...
5
+ end
data/uc.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'uc/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "uc"
8
+ spec.version = Uc::VERSION
9
+ spec.authors = ["Neeraj"]
10
+ spec.summary = %q{Unicorn controller}
11
+ spec.description = %q{Unicorn controller}
12
+ spec.homepage = ""
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.5"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_runtime_dependency "posix_mq", "~> 2.1"
23
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: uc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Neeraj
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: posix_mq
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.1'
55
+ description: Unicorn controller
56
+ email:
57
+ executables:
58
+ - uc
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - bin/uc
68
+ - lib/uc.rb
69
+ - lib/uc/error.rb
70
+ - lib/uc/logger.rb
71
+ - lib/uc/mqueue.rb
72
+ - lib/uc/server.rb
73
+ - lib/uc/shell_helper.rb
74
+ - lib/uc/unicorn.rb
75
+ - lib/uc/version.rb
76
+ - uc.gemspec
77
+ homepage: ''
78
+ licenses:
79
+ - MIT
80
+ metadata: {}
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 2.2.0
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: Unicorn controller
101
+ test_files: []