run_in_background 0.0.11 → 1.0.0
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/bin/run_in_background/daemon_wrapper +20 -20
- data/lib/run_in_background/version.rb +2 -4
- data/lib/run_in_background.rb +368 -370
- data/test/run_in_background/run_in_background_test.rb +101 -103
- data/test/run_in_background/test_app +10 -10
- metadata +3 -3
@@ -22,17 +22,17 @@ rescue LoadError
|
|
22
22
|
require 'log'
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
Params['log_write_to_console'] = false
|
26
26
|
# On WindowsXP log can be found under:
|
27
27
|
# C:/Documents and Settings/NetworkService/.bbfs/daemon_wrapper_<pid>.log
|
28
|
-
|
29
|
-
|
28
|
+
Params['log_file_name'] = File.join(Dir.home, '.bbfs', "#{File.basename(__FILE__)}_#{Process.pid}.log")
|
29
|
+
Log.init
|
30
30
|
|
31
31
|
class WrapperDaemon < Daemon
|
32
32
|
def service_main
|
33
|
-
|
33
|
+
Log.info "Wrapper starts: #{ARGV.join(' ')}"
|
34
34
|
@pid = Process.spawn ARGV.join(' ')
|
35
|
-
|
35
|
+
Log.debug1 "Wrapper inner app pid: #{@pid}"
|
36
36
|
|
37
37
|
while running?
|
38
38
|
begin
|
@@ -40,7 +40,7 @@ class WrapperDaemon < Daemon
|
|
40
40
|
Process.kill 0, @pid
|
41
41
|
rescue Errno::ESRCH
|
42
42
|
# if inner application exited then stop the service
|
43
|
-
|
43
|
+
Log.debug1 'Inner app no more running.'
|
44
44
|
service_stop
|
45
45
|
end
|
46
46
|
sleep 0.5
|
@@ -64,49 +64,49 @@ class WrapperDaemon < Daemon
|
|
64
64
|
begin
|
65
65
|
Process.kill sig, @pid # kill the inner application
|
66
66
|
rescue Exception => e
|
67
|
-
|
67
|
+
Log.debug1 "kill inner app with #{sig} signal failed: #{e.message}"
|
68
68
|
sleep 1
|
69
69
|
Process.kill sig, @pid # second try to kill the inner application
|
70
70
|
end
|
71
71
|
if alive? @pid
|
72
|
-
|
72
|
+
Log.debug1 'inner app still alive after kill. wait till exit...'
|
73
73
|
# may be redundant. children processes on Windows look be detached.
|
74
74
|
# also can be rather dangerous to use here.
|
75
75
|
pid_exit_stat = Process.waitpid2 @pid
|
76
|
-
|
76
|
+
Log.debug1 "inner application exit status: #{pid_exit_stat}"
|
77
77
|
if alive? @pid
|
78
|
-
|
78
|
+
Log.debug1 'inner app still alive after wait'
|
79
79
|
# this exception can be raised when using win32/process
|
80
80
|
raise 'inner app still alive after wait'
|
81
81
|
else
|
82
|
-
|
82
|
+
Log.debug1 'inner app deleted after wait'
|
83
83
|
end
|
84
84
|
else
|
85
|
-
|
85
|
+
Log.debug1 'inner app was killed'
|
86
86
|
end
|
87
87
|
else
|
88
88
|
# if got here then inner application is already exit. do nothing.
|
89
|
-
|
89
|
+
Log.debug1 'inner app already deleted'
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
93
93
|
def service_stop
|
94
|
-
|
94
|
+
Log.debug1 'service should be stopped'
|
95
95
|
[1, 2, 6, 15, 22, 9].each do |sig|
|
96
96
|
begin
|
97
|
-
|
97
|
+
Log.debug1 "signal #{sig} sent to kill inner app"
|
98
98
|
kill_inner_app sig
|
99
99
|
rescue Exception => e
|
100
|
-
|
100
|
+
Log.debug1 "#{e.message}"
|
101
101
|
next
|
102
102
|
end
|
103
|
-
|
103
|
+
Log.debug1 'Wrapper was stopped'
|
104
104
|
# let log be written
|
105
|
-
sleep
|
105
|
+
sleep Params['log_param_max_elapsed_time_in_seconds_from_last_flush'] + 0.5
|
106
106
|
exit!
|
107
107
|
end
|
108
|
-
|
109
|
-
sleep
|
108
|
+
Log.error 'Failed to stop service'
|
109
|
+
sleep Params['log_param_max_elapsed_time_in_seconds_from_last_flush'] + 0.5
|
110
110
|
#exit!
|
111
111
|
raise 'Failed to stop service'
|
112
112
|
end
|
data/lib/run_in_background.rb
CHANGED
@@ -4,430 +4,428 @@
|
|
4
4
|
require 'params'
|
5
5
|
require 'log'
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
Params.string('bg_command', nil, 'Server\'s command. Commands are: start, delete and nil for' \
|
7
|
+
# This library provides a basic cross-platform functionality to run arbitrary ruby scripts
|
8
|
+
# in background and control them. <br>Supported platforms: Windows, Linux, Mac
|
9
|
+
# NOTE UAC (User Account Control) should be disabled to use library on Windows 7:
|
10
|
+
# * Click on the Windows Icon
|
11
|
+
# * Click on the Control Panel
|
12
|
+
# * Type in UAC in the search box (up-right corner of your window)
|
13
|
+
# * Click on "Change User Account Control settings"
|
14
|
+
# * Drag the slider down to either "Notify me when programs try to make changes to my computer"
|
15
|
+
# or to disable it completely
|
16
|
+
# * Reboot your computer when you're ready
|
17
|
+
# == General Limitations:
|
18
|
+
# * Only ruby scripts can be run in background.
|
19
|
+
# * No multiple instances with the same name.
|
20
|
+
# == Notes:
|
21
|
+
# * Linux/Mac specific methods have _linux suffix
|
22
|
+
# * Windows specific methods have _windows suffix
|
23
|
+
# * While enhancing windows code, take care that paths are in windows format,
|
24
|
+
# <br>e.i. with "\\" file separator while ruby by default uses a "/"
|
25
|
+
# * Additional functionality such as restart, reload, etc. will be added on demand
|
26
|
+
# * Remains support to provide platform specific options for start.
|
27
|
+
# <br>For more information regarding such options
|
28
|
+
# see documentation for win32-sevice (Windows), daemons (Linux/Mac)
|
29
|
+
# == Linux Notes:
|
30
|
+
# * <tt>pid_dir</tt> parameter contains absolute path to directory where pid files will be stored.
|
31
|
+
# <br>If directory doesn't exists then it will be created.
|
32
|
+
# <br>User should have a read/write permissions to this location.
|
33
|
+
# <br>Default location: <tt>$HOME/.bbfs/pids</tt>
|
34
|
+
# * User should check that default pid directory is free from pid files of "killed" daemons.
|
35
|
+
# <br>It may happen, for example, when system finished in abnormal way then pid files were
|
36
|
+
# not deleted by daemons library.
|
37
|
+
# <br>In such case incorrect results can be received, for example for <tt>exists?</tt> method
|
38
|
+
# <br>One of the suggested methods can be before starting a daemon to check with <tt>exists?</tt>
|
39
|
+
# method whether daemon already exists and with <tt>running?</tt> method does it running.
|
40
|
+
module RunInBackground
|
41
|
+
Params.string('bg_command', nil, 'Server\'s command. Commands are: start, delete and nil for' \
|
43
42
|
' not running in background.')
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
43
|
+
Params.string('service_name', File.basename($0), 'Background service name.')
|
44
|
+
|
45
|
+
# Maximal time in seconds to wait until OS will finish a requested operation,
|
46
|
+
# e.g. daemon start/delete.
|
47
|
+
TIMEOUT = 20
|
48
|
+
|
49
|
+
if RUBY_PLATFORM =~ /linux/ or RUBY_PLATFORM =~ /darwin/
|
50
|
+
begin
|
51
|
+
require 'daemons'
|
52
|
+
require 'fileutils'
|
53
|
+
rescue LoadError
|
54
|
+
require 'rubygems'
|
55
|
+
require 'daemons'
|
56
|
+
require 'fileutils'
|
57
|
+
end
|
59
58
|
|
60
|
-
|
61
|
-
|
62
|
-
|
59
|
+
OS = :LINUX
|
60
|
+
Params.string('pid_dir', File.expand_path(File.join(Dir.home, '.bbfs', 'pids')),
|
61
|
+
'Absolute path to directory, where pid files will be stored. ' + \
|
63
62
|
'User should have a read/write permissions to this location. ' + \
|
64
63
|
'If absent then it will be created. ' + \
|
65
64
|
'It\'s actual only for Linux/Mac. ' + \
|
66
65
|
'For more information see documentation on daemons module. ' +\
|
67
66
|
'Default location is: $HOME/.bbfs/pids')
|
68
67
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
73
|
-
unless File.readable?(Params['pid_dir']) && File.writable?(Params['pid_dir'])
|
74
|
-
raise IOError.new("you should have read/write permissions to pid dir: #{Params['pid_dir']}")
|
75
|
-
end
|
76
|
-
else
|
77
|
-
::FileUtils.mkdir_p Params['pid_dir']
|
68
|
+
if Dir.exists? Params['pid_dir']
|
69
|
+
unless File.directory? Params['pid_dir']
|
70
|
+
raise IOError.new("pid directory #{Params['pid_dir']} should be a directory")
|
78
71
|
end
|
79
|
-
|
80
|
-
|
81
|
-
begin
|
82
|
-
require 'win32/service'
|
83
|
-
require 'win32/daemon'
|
84
|
-
rescue LoadError
|
85
|
-
require 'rubygems'
|
86
|
-
require 'win32/service'
|
87
|
-
require 'win32/daemon'
|
72
|
+
unless File.readable?(Params['pid_dir']) && File.writable?(Params['pid_dir'])
|
73
|
+
raise IOError.new("you should have read/write permissions to pid dir: #{Params['pid_dir']}")
|
88
74
|
end
|
89
|
-
include Win32
|
90
|
-
|
91
|
-
OS = :WINDOWS
|
92
|
-
# Get ruby interpreter path. Need it to run ruby binary.
|
93
|
-
# <br>TODO check whether this code works with Windows Ruby Version Management (e.g. Pik)
|
94
|
-
RUBY_INTERPRETER_PATH = File.join(Config::CONFIG["bindir"],
|
95
|
-
Config::CONFIG["RUBY_INSTALL_NAME"] +
|
96
|
-
Config::CONFIG["EXEEXT"]).tr!('/','\\')
|
97
|
-
|
98
|
-
# Path has to be absolute cause Win32-Service demands it.
|
99
|
-
wrapper = File.join(File.dirname(__FILE__), "..", "bin", File.basename(__FILE__, ".rb"), "daemon_wrapper")
|
100
|
-
# Wrapper script, that can receive commands from Windows Service Control and run user script,
|
101
|
-
# <br> provided as it's argument
|
102
|
-
WRAPPER_SCRIPT = File.expand_path(wrapper).tr!('/','\\')
|
103
75
|
else
|
104
|
-
|
76
|
+
::FileUtils.mkdir_p Params['pid_dir']
|
77
|
+
end
|
78
|
+
elsif RUBY_PLATFORM =~ /mingw/ or RUBY_PLATFORM =~ /ms/ or RUBY_PLATFORM =~ /win/
|
79
|
+
require 'rbconfig'
|
80
|
+
begin
|
81
|
+
require 'win32/service'
|
82
|
+
require 'win32/daemon'
|
83
|
+
rescue LoadError
|
84
|
+
require 'rubygems'
|
85
|
+
require 'win32/service'
|
86
|
+
require 'win32/daemon'
|
105
87
|
end
|
88
|
+
include Win32
|
89
|
+
|
90
|
+
OS = :WINDOWS
|
91
|
+
# Get ruby interpreter path. Need it to run ruby binary.
|
92
|
+
# <br>TODO check whether this code works with Windows Ruby Version Management (e.g. Pik)
|
93
|
+
RUBY_INTERPRETER_PATH = File.join(Config::CONFIG["bindir"],
|
94
|
+
Config::CONFIG["RUBY_INSTALL_NAME"] +
|
95
|
+
Config::CONFIG["EXEEXT"]).tr!('/','\\')
|
96
|
+
|
97
|
+
# Path has to be absolute cause Win32-Service demands it.
|
98
|
+
wrapper = File.join(File.dirname(__FILE__), "..", "bin", File.basename(__FILE__, ".rb"), "daemon_wrapper")
|
99
|
+
# Wrapper script, that can receive commands from Windows Service Control and run user script,
|
100
|
+
# <br> provided as it's argument
|
101
|
+
WRAPPER_SCRIPT = File.expand_path(wrapper).tr!('/','\\')
|
102
|
+
else
|
103
|
+
raise "Unsupported platform #{RUBY_PLATFORM}"
|
104
|
+
end
|
106
105
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
106
|
+
# Start a service/daemon.
|
107
|
+
# <br>It important to delete it after usage.
|
108
|
+
# ==== Arguments
|
109
|
+
# * <tt>binary_path</tt> - absolute path to the script that should be run in background
|
110
|
+
# NOTE for Linux script should be executable and with UNIX end-of-lines (LF).
|
111
|
+
# * <tt>binary_args</tt> - Array (not nil) of script's command line arguments
|
112
|
+
# * <tt>name</tt> - service/daemon name.
|
113
|
+
# NOTE should be unique
|
114
|
+
# * <tt>opts_specific</tt> - Hash of platform specific options (only for more specific usage)
|
115
|
+
# For more information regarding such options see documentation for
|
116
|
+
# win32-sevice (Windows), daemons (Linux/Mac)
|
117
|
+
# ==== Example (LINUX)
|
118
|
+
# <tt> RunInBackground.start "/home/user/test_app", [], "daemon_test", {:monitor => true}</tt>
|
119
|
+
def RunInBackground.start binary_path, binary_args, name, opts_specific = {}
|
120
|
+
Log.debug1("executable that should be run as daemon/service: #{binary_path}")
|
121
|
+
Log.debug1("arguments: #{binary_args}")
|
122
|
+
Log.debug1("specific options: #{opts_specific}")
|
123
|
+
|
124
|
+
if binary_path == nil or binary_args == nil or name == nil
|
125
|
+
Log.error("binary path, binary args, name arguments must be defined")
|
126
|
+
raise ArgumentError.new("binary path, binary args, name arguments must be defined")
|
127
|
+
end
|
129
128
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
129
|
+
if OS == :WINDOWS
|
130
|
+
new_binary_path = String.new(binary_path)
|
131
|
+
new_binary_args = Array.new(binary_args)
|
132
|
+
wrap_windows new_binary_path, new_binary_args
|
133
|
+
start_windows new_binary_path, new_binary_args, name, opts_specific
|
134
|
+
else # OS == LINUX
|
135
|
+
start_linux binary_path, binary_args, name, opts_specific
|
136
|
+
end
|
138
137
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
end
|
145
|
-
sleep 1
|
138
|
+
0.upto(TIMEOUT) do
|
139
|
+
if exists?(name) && running?(name)
|
140
|
+
puts "daemon/service #{name} started\n"
|
141
|
+
Log.info("daemon/service #{name} started")
|
142
|
+
return
|
146
143
|
end
|
147
|
-
|
148
|
-
delete name if exists? name
|
149
|
-
Log.error("daemon/service #{name} wasn't started in timely manner")
|
150
|
-
sleep(Params['log_param_max_elapsed_time_in_seconds_from_last_flush'] + 0.5)
|
151
|
-
raise "daemon/service #{name} wasn't started in timely manner"
|
144
|
+
sleep 1
|
152
145
|
end
|
146
|
+
# if got here then something gone wrong and daemon/service wasn't started in timely manner
|
147
|
+
delete name if exists? name
|
148
|
+
Log.error("daemon/service #{name} wasn't started in timely manner")
|
149
|
+
sleep(Params['log_param_max_elapsed_time_in_seconds_from_last_flush'] + 0.5)
|
150
|
+
raise "daemon/service #{name} wasn't started in timely manner"
|
151
|
+
end
|
153
152
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
153
|
+
def RunInBackground.start_linux binary_path, binary_args, name, opts = {}
|
154
|
+
unless File.executable? binary_path
|
155
|
+
raise ArgumentError.new("#{binary_path} is not executable.")
|
156
|
+
end
|
158
157
|
|
159
|
-
|
160
|
-
|
161
|
-
|
158
|
+
if opts.has_key? :dir
|
159
|
+
raise ArgumentError.new("No support for user-defined pid directories. See help")
|
160
|
+
end
|
162
161
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
162
|
+
opts[:app_name] = name
|
163
|
+
opts[:ARGV] = ['start']
|
164
|
+
(opts[:ARGV] << '--').concat(binary_args) if !binary_args.nil? && binary_args.size > 0
|
165
|
+
opts[:dir] = Params['pid_dir']
|
166
|
+
opts[:dir_mode] = :normal
|
168
167
|
|
169
|
-
|
170
|
-
|
168
|
+
Log.debug1("binary path: #{binary_path}")
|
169
|
+
Log.debug1("opts: #{opts}")
|
171
170
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
end
|
177
|
-
Process.waitpid pid
|
171
|
+
# Current process, that creates daemon, will transfer control to the Daemons library.
|
172
|
+
# So to continue working with current process, daemon creation initiated from separate process.
|
173
|
+
pid = fork do
|
174
|
+
Daemons.run binary_path, opts
|
178
175
|
end
|
176
|
+
Process.waitpid pid
|
177
|
+
end
|
179
178
|
|
180
|
-
|
181
|
-
|
179
|
+
def RunInBackground.start_windows binary_path, binary_args, name, opts = {}
|
180
|
+
raise ArgumentError.new("#{binary_path} doesn't exist'") unless File.exists? binary_path
|
182
181
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
182
|
+
# path that contains spaces must be escaped to be interpreted correctly
|
183
|
+
binary_path = %Q{"#{binary_path}"} if binary_path =~ / /
|
184
|
+
binary_path.tr!('/','\\')
|
185
|
+
# service should be run with the same load path as a current application
|
186
|
+
load_path = get_load_path
|
187
|
+
binary_args_str = binary_args.join ' '
|
189
188
|
|
190
|
-
|
189
|
+
opts[:binary_path_name] = \
|
191
190
|
"#{RUBY_INTERPRETER_PATH} #{load_path} #{binary_path} #{binary_args_str}"
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
end
|
191
|
+
# quotation marks must be escaped cause of ARGV parsing
|
192
|
+
opts[:binary_path_name] = opts[:binary_path_name].gsub '"', '"\\"'
|
193
|
+
opts[:service_name] = name
|
194
|
+
opts[:description] = name unless opts.has_key? :description
|
195
|
+
opts[:display_name] = name unless opts.has_key? :display_name
|
196
|
+
opts[:service_type] = Service::WIN32_OWN_PROCESS unless opts.has_key? :service_type
|
197
|
+
opts[:start_type] = Service::DEMAND_START unless opts.has_key? :start_type
|
198
|
+
|
199
|
+
# NOTE most of examples uses these dependencies. Meanwhile no explanations were found
|
200
|
+
opts[:dependencies] = ['W32Time','Schedule'] unless opts.has_key? :dependencies
|
201
|
+
# NOTE most of examples uses this option as defined beneath. The default is nil.
|
202
|
+
#opts[:load_order_group] = 'Network' unless opts.has_key? :load_order_group
|
203
|
+
|
204
|
+
Log.debug1("create service options: #{opts}")
|
205
|
+
Service.create(opts)
|
206
|
+
begin
|
207
|
+
Service.start(opts[:service_name])
|
208
|
+
rescue
|
209
|
+
Service.delete(opts[:service_name]) if Service.exists?(opts[:service_name])
|
210
|
+
raise
|
213
211
|
end
|
212
|
+
end
|
214
213
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
214
|
+
# Rerun current script in background.
|
215
|
+
# <br>Current process will be closed.
|
216
|
+
# <br>It suggested to remove from ARGV any command line arguments that point
|
217
|
+
# to run script in background, <br>otherwise an unexpexted result can be received
|
218
|
+
def RunInBackground.start! name, opts = {}
|
219
|
+
# $0 is the executable name.
|
220
|
+
start(File.expand_path($0), ARGV, name, opts)
|
221
|
+
sleep Params['log_param_max_elapsed_time_in_seconds_from_last_flush'] + 0.5
|
222
|
+
exit!
|
223
|
+
end
|
225
224
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
end
|
247
|
-
sleep 1
|
225
|
+
# Run in background script that was written as Windows Service, i.e. can receive signals
|
226
|
+
# from Service Control.
|
227
|
+
# <br>The code that is run in this script should be an extension of Win32::Daemon class.
|
228
|
+
# <br>For more information see Win32::Daemon help and examples.
|
229
|
+
# <br>No need to wrap such a script.
|
230
|
+
def RunInBackground.start_win32service binary_path, binary_args, name, opts_specific = {}
|
231
|
+
Log.debug1("executable that should be run as service: #{binary_path}")
|
232
|
+
Log.debug1("arguments: #{binary_args}")
|
233
|
+
Log.debug1("specific options: #{opts_specific}")
|
234
|
+
|
235
|
+
if OS == :WINDOWS
|
236
|
+
start_windows binary_path, binary_args, name, opts_specific
|
237
|
+
else # OS == :LINUX
|
238
|
+
raise NotImplementedError.new("Unsupported method on #{OS}")
|
239
|
+
end
|
240
|
+
0.upto(TIMEOUT) do
|
241
|
+
if exists?(name) && running?(name)
|
242
|
+
puts "windows service #{name} started\n"
|
243
|
+
Log.info("windows service #{name} started")
|
244
|
+
return
|
248
245
|
end
|
249
|
-
|
250
|
-
delete name if exists? name
|
251
|
-
Log.error("daemon/service #{name} wasn't started in timely manner")
|
252
|
-
sleep(Params['log_param_max_elapsed_time_in_seconds_from_last_flush'] + 0.5)
|
253
|
-
raise "daemon/service #{name} wasn't started in timely manner"
|
246
|
+
sleep 1
|
254
247
|
end
|
248
|
+
# if got here then something gone wrong and daemon/service wasn't started in timely manner
|
249
|
+
delete name if exists? name
|
250
|
+
Log.error("daemon/service #{name} wasn't started in timely manner")
|
251
|
+
sleep(Params['log_param_max_elapsed_time_in_seconds_from_last_flush'] + 0.5)
|
252
|
+
raise "daemon/service #{name} wasn't started in timely manner"
|
253
|
+
end
|
255
254
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
255
|
+
# Wrap an arbitrary ruby script withing script that can be run as Windows Service.
|
256
|
+
# ==== Arguments
|
257
|
+
# * <tt>binary_path</tt> - absolute path of the script that should be run in background
|
258
|
+
# * <tt>binary_args</tt> - array (not nil) of scripts command line arguments
|
259
|
+
#
|
260
|
+
# NOTE binary_path and binary_args contents will be change
|
261
|
+
def RunInBackground.wrap_windows binary_path, binary_args
|
262
|
+
raise ArgumentError.new("#{binary_path} doesn't exists") unless File.exists? binary_path
|
263
|
+
|
264
|
+
# service should be run with the same load path as a current application
|
265
|
+
load_path = get_load_path
|
266
|
+
# path that contains spaces must be escaped to be interpreted correctly
|
267
|
+
binary_path = %Q{"#{binary_path}"} if binary_path =~ / /
|
268
|
+
binary_args.insert(0, RUBY_INTERPRETER_PATH, load_path, binary_path.tr('/','\\'))
|
269
|
+
binary_path.replace(WRAPPER_SCRIPT)
|
270
|
+
end
|
272
271
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
end
|
272
|
+
# NOTE if this method will become public then may be needed to change appropriately wrapper script
|
273
|
+
def RunInBackground.stop name
|
274
|
+
if not exists? name
|
275
|
+
raise ArgumentError.new("Daemon #{name} doesn't exists")
|
276
|
+
elsif OS == :WINDOWS
|
277
|
+
Service.stop(name)
|
278
|
+
else # OS == :LINUX
|
279
|
+
opts = {:app_name => name,
|
280
|
+
:ARGV => ['stop'],
|
281
|
+
:dir_mode => :normal,
|
282
|
+
:dir => Params['pid_dir']
|
283
|
+
}
|
284
|
+
# Current process, that creates daemon, will transfer control to the Daemons library.
|
285
|
+
# So to continue working with current process, daemon creation initiated from separate process.
|
286
|
+
# It looks that it holds only for start command
|
287
|
+
#pid = fork do
|
288
|
+
Daemons.run "", opts
|
289
|
+
#end
|
290
|
+
#Process.waitpid pid
|
293
291
|
end
|
292
|
+
end
|
294
293
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
end
|
303
|
-
if OS == :WINDOWS
|
304
|
-
Service.delete name
|
305
|
-
else # OS == :LINUX
|
306
|
-
opts = {:app_name => name,
|
307
|
-
:ARGV => ['zap'],
|
308
|
-
:dir_mode => :normal,
|
309
|
-
:dir => Params['pid_dir']
|
310
|
-
}
|
311
|
-
# Current process, that creates daemon, will transfer control to the Daemons library.
|
312
|
-
# So to continue working with current process, daemon creation initiated from separate process.
|
313
|
-
# It looks that it holds only for start command
|
314
|
-
#pid = fork do
|
315
|
-
Daemons.run "", opts
|
316
|
-
#end
|
317
|
-
#Process.waitpid pid
|
318
|
-
end
|
319
|
-
0.upto(TIMEOUT) do
|
320
|
-
unless exists? name
|
321
|
-
puts "daemon/service #{name} deleted\n"
|
322
|
-
Log.info("daemon/service #{name} deleted")
|
323
|
-
return
|
324
|
-
end
|
325
|
-
sleep 1
|
326
|
-
end
|
327
|
-
# if got here then something gone wrong and daemon/service wasn't deleted in timely manner
|
328
|
-
Log.error("daemon/service #{name} wasn't deleted in timely manner")
|
329
|
-
sleep(Params['log_param_max_elapsed_time_in_seconds_from_last_flush'] + 0.5)
|
330
|
-
raise "daemon/service #{name} wasn't deleted in timely manner"
|
294
|
+
# Delete service/daemon.
|
295
|
+
# <br>If running then stop and delete.
|
296
|
+
def RunInBackground.delete name
|
297
|
+
if not exists? name
|
298
|
+
raise ArgumentError.new("Daemon #{name} doesn't exists")
|
299
|
+
elsif running? name
|
300
|
+
stop name
|
331
301
|
end
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
302
|
+
if OS == :WINDOWS
|
303
|
+
Service.delete name
|
304
|
+
else # OS == :LINUX
|
305
|
+
opts = {:app_name => name,
|
306
|
+
:ARGV => ['zap'],
|
307
|
+
:dir_mode => :normal,
|
308
|
+
:dir => Params['pid_dir']
|
309
|
+
}
|
310
|
+
# Current process, that creates daemon, will transfer control to the Daemons library.
|
311
|
+
# So to continue working with current process, daemon creation initiated from separate process.
|
312
|
+
# It looks that it holds only for start command
|
313
|
+
#pid = fork do
|
314
|
+
Daemons.run "", opts
|
315
|
+
#end
|
316
|
+
#Process.waitpid pid
|
317
|
+
end
|
318
|
+
0.upto(TIMEOUT) do
|
319
|
+
unless exists? name
|
320
|
+
puts "daemon/service #{name} deleted\n"
|
321
|
+
Log.info("daemon/service #{name} deleted")
|
322
|
+
return
|
341
323
|
end
|
324
|
+
sleep 1
|
342
325
|
end
|
326
|
+
# if got here then something gone wrong and daemon/service wasn't deleted in timely manner
|
327
|
+
Log.error("daemon/service #{name} wasn't deleted in timely manner")
|
328
|
+
sleep(Params['log_param_max_elapsed_time_in_seconds_from_last_flush'] + 0.5)
|
329
|
+
raise "daemon/service #{name} wasn't deleted in timely manner"
|
330
|
+
end
|
343
331
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
332
|
+
def RunInBackground.exists? name
|
333
|
+
if name == nil
|
334
|
+
raise ArgumentError.new("service/daemon name argument must be defined")
|
335
|
+
elsif OS == :WINDOWS
|
336
|
+
Service.exists? name
|
337
|
+
else # OS == :LINUX
|
338
|
+
pid_files = Daemons::PidFile.find_files(Params['pid_dir'], name)
|
339
|
+
pid_files != nil && pid_files.size > 0
|
352
340
|
end
|
341
|
+
end
|
353
342
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
343
|
+
def RunInBackground.running? name
|
344
|
+
if not exists? name
|
345
|
+
raise ArgumentError.new("Daemon #{name} doesn't exists")
|
346
|
+
elsif OS == :WINDOWS
|
347
|
+
Service.status(name).current_state == 'running'
|
348
|
+
else # OS == :LINUX
|
349
|
+
Daemons::Pid.running? name
|
360
350
|
end
|
351
|
+
end
|
361
352
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
353
|
+
# Returns absolute standard form of the path.
|
354
|
+
# It includes path separators accepted on this OS
|
355
|
+
def RunInBackground.get_abs_std_path path
|
356
|
+
path = File.expand_path path
|
357
|
+
path = path.tr('/','\\') if OS == :WINDOWS
|
358
|
+
path
|
359
|
+
end
|
360
|
+
|
361
|
+
# Returns load path as it provided in command line.
|
362
|
+
def RunInBackground.get_load_path
|
363
|
+
load_path = Array.new
|
364
|
+
$:.each do |location|
|
365
|
+
load_path << %Q{-I"#{get_abs_std_path(location)}"}
|
369
366
|
end
|
367
|
+
load_path.join ' '
|
368
|
+
end
|
370
369
|
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
370
|
+
# Prepare ARGV so it can be provided as a command line arguments.
|
371
|
+
# Remove bg_command from ARGV to prevent infinite recursion.
|
372
|
+
def RunInBackground.prepare_argv
|
373
|
+
new_argv = Array.new
|
374
|
+
ARGV.each do |arg|
|
375
|
+
# For each argument try splitting to 'name'='value'
|
376
|
+
arg_arr = arg.split '='
|
377
|
+
# If no '=' is argument, just copy paste.
|
378
|
+
if arg_arr.size == 1
|
379
|
+
arg = "\"#{arg}\"" if arg =~ / /
|
380
|
+
new_argv << arg
|
382
381
|
# If it is a 'name'='value' argument add "" so the value can be passed as argument again.
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
end
|
389
|
-
else
|
390
|
-
Log.warning("ARGV argument #{arg} wasn't processed")
|
391
|
-
new_argv << arg
|
382
|
+
elsif arg_arr.size == 2
|
383
|
+
# Skip bg_command flag (remove infinite recursion)!
|
384
|
+
if arg_arr[0] !~ /bg_command/
|
385
|
+
arg_arr[1] = "\"#{arg_arr[1]}\"" if arg_arr[1] =~ / /
|
386
|
+
new_argv << arg_arr.join('=')
|
392
387
|
end
|
388
|
+
else
|
389
|
+
Log.warning("ARGV argument #{arg} wasn't processed")
|
390
|
+
new_argv << arg
|
393
391
|
end
|
394
|
-
ARGV.clear
|
395
|
-
ARGV.concat new_argv
|
396
392
|
end
|
393
|
+
ARGV.clear
|
394
|
+
ARGV.concat new_argv
|
395
|
+
end
|
397
396
|
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
else
|
419
|
-
msg = "Can't delete. Service #{Params['service_name']} already deleted"
|
420
|
-
puts msg
|
421
|
-
Log.warning(msg)
|
422
|
-
end
|
397
|
+
def RunInBackground.run &b
|
398
|
+
case Params['bg_command']
|
399
|
+
when nil
|
400
|
+
yield b
|
401
|
+
when 'start'
|
402
|
+
# To prevent service enter loop cause of background parameter
|
403
|
+
# all options that points to run in background must be disabled
|
404
|
+
# (for more information see documentation for RunInBackground::start!)
|
405
|
+
Params['bg_command'] = nil
|
406
|
+
RunInBackground.prepare_argv
|
407
|
+
|
408
|
+
begin
|
409
|
+
RunInBackground.start! Params['service_name']
|
410
|
+
rescue Exception => e
|
411
|
+
Log.error("Start service command failed: #{e.message}")
|
412
|
+
raise
|
413
|
+
end
|
414
|
+
when 'delete'
|
415
|
+
if RunInBackground.exists? Params['service_name']
|
416
|
+
RunInBackground.delete Params['service_name']
|
423
417
|
else
|
424
|
-
msg = "
|
418
|
+
msg = "Can't delete. Service #{Params['service_name']} already deleted"
|
425
419
|
puts msg
|
426
|
-
Log.
|
427
|
-
|
420
|
+
Log.warning(msg)
|
421
|
+
end
|
422
|
+
else
|
423
|
+
msg = "Unsupported command #{Params['bg_command']}. Supported commands are: start, delete"
|
424
|
+
puts msg
|
425
|
+
Log.error(msg)
|
428
426
|
end
|
427
|
+
end
|
429
428
|
|
430
|
-
|
429
|
+
private_class_method :start_linux, :start_windows, :wrap_windows, :stop, :get_abs_std_path, \
|
431
430
|
:get_load_path
|
432
|
-
end
|
433
431
|
end
|
@@ -1,124 +1,122 @@
|
|
1
1
|
require 'test/unit'
|
2
2
|
require 'run_in_background'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
#include BBFS::RunInBackground
|
4
|
+
# TODO break to number of small tests according to functionality
|
5
|
+
# TODO rewrite with Shoulda/RSpec
|
6
|
+
class TestRunInBackground < Test::Unit::TestCase
|
7
|
+
#include RunInBackground
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
9
|
+
if RUBY_PLATFORM =~ /linux/ or RUBY_PLATFORM =~ /darwin/
|
10
|
+
OS = :LINUX
|
11
|
+
elsif RUBY_PLATFORM =~ /mingw/ or RUBY_PLATFORM =~ /ms/ or RUBY_PLATFORM =~ /win/
|
12
|
+
require 'sys/uname'
|
13
|
+
OS = :WINDOWS
|
14
|
+
else
|
15
|
+
raise "Unsupported platform #{RUBY_PLATFORM}"
|
16
|
+
end
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
18
|
+
def setup
|
19
|
+
@good_daemon = "good_daemon_test"
|
20
|
+
@good_daemonize = "good_daemonize_test"
|
21
|
+
@good_win32daemon = "good_win32daemon_test"
|
22
|
+
@bad_daemon = "bad_daemon_test"
|
23
|
+
@binary = File.join(File.dirname(File.expand_path(__FILE__)), 'test_app')
|
24
|
+
@binary.tr!('/','\\') if OS == :WINDOWS
|
25
|
+
File.chmod(0755, @binary) if OS == :LINUX && !File.executable?(@binary)
|
26
|
+
@absent_binary = File.join(File.dirname(File.expand_path(__FILE__)), "test_app_absent")
|
27
|
+
end
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
def test_functionality
|
30
|
+
if OS == :WINDOWS && Sys::Uname.sysname =~ /(Windows 7)/
|
31
|
+
skip "This test shouldn't be run on #{$1}"
|
32
|
+
end
|
34
33
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
# test start
|
35
|
+
# test application should actually start here
|
36
|
+
assert_nothing_raised{ RunInBackground.start(@binary, ["1000"], @good_daemon) }
|
37
|
+
assert_raise(ArgumentError) { RunInBackground.start(@absent_binary, ["1000"], @bad_daemon) }
|
39
38
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
39
|
+
# start arguments have to be defined
|
40
|
+
assert_raise(ArgumentError) { RunInBackground.start(["1000"], @bad_daemon) }
|
41
|
+
assert_raise(ArgumentError) { RunInBackground.start(nil, ["1000"], @bad_daemon) }
|
42
|
+
assert_raise(ArgumentError) { RunInBackground.start(@absent_binary, nil, @bad_daemon) }
|
43
|
+
assert_raise(ArgumentError) { RunInBackground.start(@absent_binary, ["1000"], nil) }
|
45
44
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
45
|
+
# test exists?
|
46
|
+
assert_raise(ArgumentError) { RunInBackground.exists? }
|
47
|
+
assert_equal(false, RunInBackground.exists?(@bad_daemon))
|
48
|
+
assert_equal(true, RunInBackground.exists?(@good_daemon))
|
50
49
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
50
|
+
# test running?
|
51
|
+
# if stop method will be public need to add test checks actually stopped daemon
|
52
|
+
assert_raise(ArgumentError) { RunInBackground.running? }
|
53
|
+
assert_raise(ArgumentError) { RunInBackground.running?(@bad_daemon) }
|
54
|
+
assert_equal(true, RunInBackground.running?(@good_daemon))
|
56
55
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
72
|
-
sleep 1
|
56
|
+
# test daemonazing (start!)
|
57
|
+
# from the nature of daemonization need to run it from another process that will be daemonized
|
58
|
+
ruby = (OS == :WINDOWS ? RunInBackground::RUBY_INTERPRETER_PATH : "ruby")
|
59
|
+
cmd = "#{ruby} -Ilib #{@binary} 50 #{@good_daemonize}"
|
60
|
+
pid = spawn(cmd)
|
61
|
+
Process.waitpid pid
|
62
|
+
# checking that it indeed was daemonized
|
63
|
+
# e.i. process was killed and code rerun in background
|
64
|
+
# it takes time to the OS to remove process, so using a timeout here
|
65
|
+
0.upto(RunInBackground::TIMEOUT) do
|
66
|
+
begin
|
67
|
+
Process.kill(0, pid)
|
68
|
+
rescue Errno::ESRCH
|
69
|
+
break
|
73
70
|
end
|
74
|
-
|
75
|
-
|
76
|
-
|
71
|
+
sleep 1
|
72
|
+
end
|
73
|
+
assert_raise(Errno::ESRCH) { Process.kill(0, pid) }
|
74
|
+
assert_equal(true, RunInBackground.exists?(@good_daemonize))
|
75
|
+
assert_equal(true, RunInBackground.running?(@good_daemonize))
|
77
76
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
77
|
+
# test running win32 specific daemon (start_win32service)
|
78
|
+
# wrapper script will be run
|
79
|
+
if OS == :WINDOWS
|
80
|
+
win32service_arg = [RunInBackground::RUBY_INTERPRETER_PATH, @binary, 1000]
|
81
|
+
assert_nothing_raised{
|
82
|
+
RunInBackground.start_win32service(RunInBackground::WRAPPER_SCRIPT,
|
83
|
+
win32service_arg, @good_win32daemon)
|
84
|
+
}
|
85
|
+
assert_equal(true, RunInBackground.exists?(@good_win32daemon))
|
86
|
+
assert_equal(true, RunInBackground.running?(@good_win32daemon))
|
87
|
+
else
|
88
|
+
assert_raise(NotImplementedError) {
|
89
|
+
RunInBackground.start_win32service(@absent_binary, [], @bad_daemon)
|
90
|
+
}
|
91
|
+
end
|
93
92
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
93
|
+
# uncomment following lines if there is a suspicion that something gone wrong
|
94
|
+
# inspired by bug caused by coworking of daemon_wrapper an logger
|
95
|
+
#sleep 10
|
96
|
+
#assert_equal(true, RunInBackground.running?(@good_daemon))
|
97
|
+
#assert_equal(true, RunInBackground.running?(@good_daemonize))
|
98
|
+
#assert_equal(true, RunInBackground.running?(@good_win32daemon))
|
100
99
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
100
|
+
# test delete
|
101
|
+
# test application should actually stop here
|
102
|
+
assert_raise(ArgumentError) { RunInBackground.delete }
|
103
|
+
assert_raise(ArgumentError) { RunInBackground.delete(@bad_daemon) }
|
104
|
+
assert_nothing_raised { RunInBackground.delete(@good_daemon) }
|
105
|
+
assert_equal(false, RunInBackground.exists?(@good_daemon))
|
107
106
|
|
108
|
-
|
109
|
-
|
107
|
+
assert_nothing_raised { RunInBackground.delete(@good_daemonize) }
|
108
|
+
assert_equal(false, RunInBackground.exists?(@good_daemonize))
|
110
109
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
end
|
110
|
+
# actuall only for Windows platform
|
111
|
+
if RunInBackground.exists?(@good_win32daemon)
|
112
|
+
assert_nothing_raised { RunInBackground.delete(@good_win32daemon) }
|
113
|
+
assert_equal(false, RunInBackground.exists?(@good_win32daemon))
|
116
114
|
end
|
115
|
+
end
|
117
116
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
end
|
117
|
+
def teardown
|
118
|
+
RunInBackground.delete @good_daemon if RunInBackground.exists? @good_daemon
|
119
|
+
RunInBackground.delete @good_daemonize if RunInBackground.exists? @good_daemonize
|
120
|
+
RunInBackground.delete @good_win32daemon if RunInBackground.exists? @good_win32daemon
|
123
121
|
end
|
124
122
|
end
|
@@ -18,12 +18,12 @@ begin
|
|
18
18
|
|
19
19
|
# On WindowsXP log can be found under:
|
20
20
|
# C:/Documents and Settings/NetworkService/.bbfs/test_app_<pid>.log
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
Params['log_file_name'] = File.join(Dir.home, '.bbfs', "#{File.basename(__FILE__)}_#{Process.pid}.log")
|
22
|
+
Params['log_write_to_console'] = false
|
23
|
+
Params['log_param_max_elapsed_time_in_seconds_from_last_flush'] = 1
|
24
24
|
if DBG
|
25
|
-
|
26
|
-
|
25
|
+
Params['log_debug_level'] = 1
|
26
|
+
Log.init
|
27
27
|
end
|
28
28
|
|
29
29
|
# app should be run in background
|
@@ -36,23 +36,23 @@ begin
|
|
36
36
|
require 'run_in_background'
|
37
37
|
end
|
38
38
|
|
39
|
-
|
39
|
+
Log.debug1 "Before run in background: PID #{Process.pid}"
|
40
40
|
# ARGV.pop returns frozen string and thus causes a failure of Service.create
|
41
41
|
# to fix it new string with the same content created.
|
42
|
-
|
42
|
+
RunInBackground.start!(String.new(ARGV.pop))
|
43
43
|
# if got here then error
|
44
|
-
|
44
|
+
Log.error "After run in background: ERROR"
|
45
45
|
end
|
46
46
|
|
47
47
|
max = (ARGV.size > 0 && ARGV[0] != nil && ARGV[0].to_i > 0)? ARGV[0].to_i : 200
|
48
48
|
|
49
49
|
while max > 0
|
50
|
-
|
50
|
+
Log.debug1 "#{max}"
|
51
51
|
sleep 1
|
52
52
|
max -= 1
|
53
53
|
end
|
54
54
|
|
55
55
|
rescue Exception => err
|
56
|
-
|
56
|
+
Log.error "Wrapper error: #{err}"
|
57
57
|
raise
|
58
58
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: run_in_background
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01
|
12
|
+
date: 2013-05-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: log
|
@@ -58,7 +58,7 @@ files:
|
|
58
58
|
- test/run_in_background/test_app
|
59
59
|
- test/run_in_background/run_in_background_test.rb
|
60
60
|
- ext/run_in_background/mkrf_conf.rb
|
61
|
-
homepage: http://github.com/
|
61
|
+
homepage: http://github.com/bbfsdev/bbfs
|
62
62
|
licenses: []
|
63
63
|
post_install_message:
|
64
64
|
rdoc_options: []
|