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 +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +36 -0
- data/Gemfile +6 -0
- data/README.md +2 -0
- data/control.gemspec +22 -0
- data/lib/control/version.rb +3 -0
- data/lib/control_helper.rb +143 -0
- data/lib/process_controller.rb +64 -0
- metadata +66 -0
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
data/README.md
ADDED
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,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: []
|