process_controller 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d7675279ad00cea114fbb342f65f39949b86c474
4
+ data.tar.gz: 89d622bc7dfe864917a94b034c6b910220484452
5
+ SHA512:
6
+ metadata.gz: 380067bb93500337ed7fe84383d854364fa9d092b965525e5e9bc0cd736949d0be6b80d18d8312cdfbf447e99d6d5601bcf8b16366032cb6e0b78f4704f91049
7
+ data.tar.gz: 37b3a7510b9009b696dfed81390e8703163fe87f1b9472f68a6e9e1863bd9714aa9b47d9120faec75a11f8f172f450036f44d150c50fcc76e9e731d5b3509c0f
data/.DS_Store ADDED
Binary file
data/.gitignore ADDED
@@ -0,0 +1,36 @@
1
+ .idea/
2
+
3
+ *.gem
4
+ *.rbc
5
+ /.config
6
+ /coverage/
7
+ /InstalledFiles
8
+ /pkg/
9
+ /spec/reports/
10
+ /test/tmp/
11
+ /test/version_tmp/
12
+ /tmp/
13
+
14
+ ## Specific to RubyMotion:
15
+ .dat*
16
+ .repl_history
17
+ build/
18
+
19
+ ## Documentation cache and generated files:
20
+ /.yardoc/
21
+ /_yardoc/
22
+ /doc/
23
+ /rdoc/
24
+
25
+ ## Environment normalisation:
26
+ /.bundle/
27
+ /lib/bundler/man/
28
+
29
+ # for a library or gem, you might want to ignore these files since the code is
30
+ # intended to run in multiple environments; otherwise, check them in:
31
+ Gemfile.lock
32
+ .ruby-version
33
+ .ruby-gemset
34
+
35
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
36
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in control.gemspec
4
+ gemspec
5
+
6
+
data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # control
2
+ A Gem for stop/start/restart process
data/control.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'control/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'process_controller'
7
+ s.version = Control::VERSION
8
+ s.authors = ['ohad partuck']
9
+ s.email = ['ohadpartuck@gmail.com']
10
+ s.homepage = 'http://open-source.com'
11
+ s.licenses = ['MIT']
12
+ s.summary = %q{stop/start/restart}
13
+ s.description = %q{Generic stop/start/restart for processes}
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ # s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ # s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ['lib']
19
+
20
+ s.add_runtime_dependency 'activesupport', '~> 4.2'
21
+
22
+ end
@@ -0,0 +1,3 @@
1
+ module Control
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,143 @@
1
+ module ControlHelper
2
+ extend self
3
+
4
+ def find_app_pid(options)
5
+ pid_filename = options.fetch(Control_P::OPTIONS_ATTRIBUTES[:pid], nil)
6
+
7
+ if pid_filename
8
+ get_pid_from_file(pid_filename)
9
+ else
10
+ search_by_string = retreive_search_string(options)
11
+ find_pid_with_ps(search_by_string)
12
+ end
13
+ end
14
+
15
+ def retreive_search_string(options)
16
+ attributes = Control_P::OPTIONS_ATTRIBUTES
17
+ find_by = options.fetch(attributes[:find_pid_by], Control_P::FIND_BY_OPTIONS[:app_filename])
18
+ #TODO validate find_by is in Control_P::FIND_BY_OPTIONS
19
+ search_string = options.fetch(attributes[find_by], nil)
20
+ raise "no idea how to search for old pid. find_by is #{find_by}" if search_string.nil?
21
+
22
+ search_string
23
+ end
24
+
25
+ def get_pid_from_file(pid_filename)
26
+ File.open(pid_filename, &:readline).strip
27
+ end
28
+
29
+
30
+ def find_pid_with_ps(search_by_string)
31
+ pid = nil
32
+ procs = `ps aux`
33
+
34
+ procs.each_line do |proc|
35
+ if proc.include?(search_by_string)
36
+ res = proc.split(' ')
37
+ old_pid = res[1]
38
+ return old_pid.to_i
39
+ end
40
+ end
41
+
42
+ pid
43
+ end
44
+
45
+ def exit_if_not_running!(options)
46
+ old_pid = find_app_pid(options)
47
+ unless app_running?(old_pid)
48
+ app_name = options.fetch(Control_P::OPTIONS_ATTRIBUTES[:app_name], '')
49
+
50
+ p "app #{app_name} is already NOT running"
51
+ exit(1)
52
+ end
53
+
54
+ old_pid
55
+ end
56
+
57
+ def app_running?(pid)
58
+ !pid.nil?
59
+ end
60
+
61
+ def start_a_new_process!(options)
62
+ attributes = Control_P::OPTIONS_ATTRIBUTES
63
+
64
+ start_command = options.fetch(attributes[:start_command])
65
+
66
+ p "trying to start a new using start_command: #{start_command}"
67
+
68
+ pid = spawn(start_command)
69
+ Process.detach(pid) if pid
70
+ sleep 5 # give the new app enough time to crash
71
+ find_app_pid(options)
72
+ end
73
+
74
+ def exit_if_old_process_is_already_running!(options)
75
+ p 'checking if there\'s a running process'
76
+ old_pid = find_app_pid(options)
77
+ if old_pid
78
+ p "#{app_name} is already running. old_pid is #{old_pid} exiting"
79
+ exit(1)
80
+ end
81
+ end
82
+
83
+ def kill_the_process!(options)
84
+ kill_command = options.fetch(Control_P::OPTIONS_ATTRIBUTES[:kill_command])
85
+ `#{kill_command}`
86
+ false
87
+ rescue Errno::ESRCH
88
+ p 'no such process returning true for kill_the_process!'
89
+ true
90
+ rescue => e
91
+ p "error in killing process #{e.inspect}"
92
+ end
93
+
94
+ def restart_the_app!(options)
95
+ restart_command = options.fetch(Control_P::OPTIONS_ATTRIBUTES[:restart_command])
96
+ `#{restart_command}`
97
+ end
98
+
99
+ def kill_with_retries!(options)
100
+ num_tries = 4
101
+ (1..num_tries).to_a.each do |try|
102
+ res = kill_the_process!(options)
103
+ return true if res
104
+ sleep 5
105
+ old_pid = find_app_pid(options)
106
+ if old_pid
107
+ p "error in kill process #{app_name}. found pid #{old_pid} try number #{try}"
108
+ exit(1) if try == num_tries
109
+ else
110
+ app_name = options.fetch(Control_P::OPTIONS_ATTRIBUTES[:app_name], '')
111
+ p "#{app_name}, it's dead."
112
+ return true
113
+ end
114
+ end
115
+ end
116
+
117
+ def check_for_success_in_starting_new_process!(options)
118
+ prefix = "#{Control_P::HOSTNAME}"
119
+
120
+ pid = find_app_pid(options)
121
+ if pid
122
+ p "#{prefix} Ok, Restarted. new pid #{pid}"
123
+ exit(0)
124
+ else
125
+ p "#{prefix} problem restarting. Check your code. #{pid}"
126
+ exit(1)
127
+ end
128
+ end
129
+
130
+ def kill_the_old_process_if_needed(options)
131
+
132
+ old_pid = find_app_pid(options)
133
+ if app_running?(old_pid)
134
+ # TODO should wait ??
135
+ kill_with_retries!(options)
136
+ else
137
+ app_name = options.fetch(Control_P::OPTIONS_ATTRIBUTES[:app_name], '')
138
+ p "There's no app up to restart (#{app_name}), Trying to start a new one.."
139
+ true
140
+ end
141
+ end
142
+
143
+ end
@@ -0,0 +1,64 @@
1
+ require 'socket'
2
+ require 'control_helper'
3
+ require 'active_support/core_ext/hash/indifferent_access'
4
+
5
+ class Control_P
6
+ OPTIONS_ATTRIBUTES = {action: 'action', pid: 'pid_filename', find_pid_by: 'find_pid_by',
7
+ app_name: 'app_name', port_num: 'port_num', app_filename: 'app_filename',
8
+ http_server: 'http_server', kill_command: 'kill_command',
9
+ restart_command: 'restart_command', start_command: 'start_command'}.with_indifferent_access
10
+
11
+ FIND_BY_OPTIONS = {app_filename: 'app_filename', port_num: 'port_num', app_name: 'app_name', pid_file: 'pid_file'}.with_indifferent_access
12
+ HOSTNAME = Socket.gethostname
13
+
14
+ # Main Method for all actions
15
+ def self.do(options)
16
+ options = options.with_indifferent_access
17
+ #TODO options validations
18
+ action = options.fetch(OPTIONS_ATTRIBUTES[:action], nil)
19
+
20
+ case action
21
+ when 'start'
22
+ start_actions(options)
23
+ when 'stop'
24
+ stop_actions(options)
25
+ when 'restart'
26
+ restart_actions(options)
27
+ else
28
+ raise "action #{action} not implemented"
29
+ end
30
+ end
31
+
32
+ def self.helper
33
+ ControlHelper
34
+ end
35
+
36
+ def self.restart_actions(options)
37
+
38
+ http_server = options.fetch(OPTIONS_ATTRIBUTES[:http_server], false)
39
+
40
+ #means it's seamless, just need to send a kill signal and it will restart it self
41
+ if http_server
42
+ helper.restart_the_app!(options)
43
+ else
44
+ helper.kill_the_old_process_if_needed(options)
45
+ helper.start_a_new_process!(options)
46
+ end
47
+
48
+ helper.check_for_success_in_starting_new_process!(options)
49
+ end
50
+
51
+ def self.start_actions(options)
52
+ helper.exit_if_old_process_is_already_running!(options)
53
+
54
+ helper.start_a_new_process!(options)
55
+ helper.check_for_success_in_starting_new_process!(options)
56
+ end
57
+
58
+ def self.stop_actions(options)
59
+ helper.exit_if_not_running!(options)
60
+
61
+ helper.kill_the_process!(options)
62
+ end
63
+
64
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: process_controller
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - ohad partuck
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.2'
27
+ description: Generic stop/start/restart for processes
28
+ email:
29
+ - ohadpartuck@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".DS_Store"
35
+ - ".gitignore"
36
+ - Gemfile
37
+ - README.md
38
+ - control.gemspec
39
+ - lib/control/version.rb
40
+ - lib/control_helper.rb
41
+ - lib/process_controller.rb
42
+ homepage: http://open-source.com
43
+ licenses:
44
+ - MIT
45
+ metadata: {}
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ requirements: []
61
+ rubyforge_project:
62
+ rubygems_version: 2.4.5
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: stop/start/restart
66
+ test_files: []