batchbase 0.0.2
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/.gitignore +19 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/batchbase.gemspec +26 -0
- data/example/sample1.rb +12 -0
- data/example/sample2.rb +30 -0
- data/example/sample3.rb +27 -0
- data/lib/batchbase/core.rb +273 -0
- data/lib/batchbase/version.rb +3 -0
- data/lib/batchbase.rb +8 -0
- data/readme.md +11 -0
- data/test/batch.rb +30 -0
- data/test/batch_too_long.rb +27 -0
- data/test/by_hand.rb +14 -0
- data/test/check_logger.rb +31 -0
- data/test/test.rb +321 -0
- data/test/test_helper.rb +5 -0
- metadata +101 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/batchbase.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "batchbase/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "batchbase"
|
7
|
+
s.version = Batchbase::VERSION
|
8
|
+
s.authors = ["pacojp"]
|
9
|
+
s.email = ["paco.jp@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{oreore batch base class}
|
12
|
+
s.description = %q{oreore batch base class}
|
13
|
+
s.rubyforge_project = "batchbase"
|
14
|
+
|
15
|
+
s.add_dependency "sys-proctable","0.9.1"
|
16
|
+
s.add_dependency "kanamei_log_formatter","0.0.1"
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
# specify any dependencies here; for example:
|
24
|
+
# s.add_development_dependency "rspec"
|
25
|
+
# s.add_runtime_dependency "rest-client"
|
26
|
+
end
|
data/example/sample1.rb
ADDED
data/example/sample2.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'batchbase'
|
3
|
+
|
4
|
+
# usage type 2
|
5
|
+
|
6
|
+
class Batch
|
7
|
+
include Batchbase::Core
|
8
|
+
|
9
|
+
def proceed
|
10
|
+
opts = self.option_parser
|
11
|
+
opts.on("-f", "--favorite_number=value",
|
12
|
+
Integer,"favo"
|
13
|
+
) do |v|
|
14
|
+
env[:favorite_number] = v
|
15
|
+
end
|
16
|
+
|
17
|
+
execute do
|
18
|
+
logger.info env.inspect
|
19
|
+
if env[:favorite_number]
|
20
|
+
logger.info env[:favorite_number].to_s
|
21
|
+
else
|
22
|
+
logger.info 'fovorite_number not set'
|
23
|
+
end
|
24
|
+
logger.info 'info message'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
b = Batch.new
|
30
|
+
b.proceed
|
data/example/sample3.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'batchbase'
|
4
|
+
|
5
|
+
# usage type 3
|
6
|
+
|
7
|
+
include Batchbase::Core
|
8
|
+
create_logger('/tmp/batchbase_test_sample3.log')
|
9
|
+
|
10
|
+
def receive_signal(signal)
|
11
|
+
logger.info("receive signal #{signal}")
|
12
|
+
@stop = true
|
13
|
+
end
|
14
|
+
|
15
|
+
@stop = false
|
16
|
+
|
17
|
+
set_signal_observer(:receive_signal)
|
18
|
+
|
19
|
+
execute(:daemonize=>true) do
|
20
|
+
logger.info 'test'
|
21
|
+
logger.info env[:pid_file]
|
22
|
+
3600.times do
|
23
|
+
logger.info Time.now.strftime("%Y/%m/%d %H:%M:%S")
|
24
|
+
sleep 1
|
25
|
+
break if @stop
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,273 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'digest/md5'
|
3
|
+
require "optparse"
|
4
|
+
require 'sys/proctable'
|
5
|
+
require 'logger'
|
6
|
+
require 'kanamei_log_formatter'
|
7
|
+
|
8
|
+
module Batchbase
|
9
|
+
module Core
|
10
|
+
|
11
|
+
SIGNALS = [ :QUIT, :INT, :TERM, :USR1, :USR2, :HUP ]
|
12
|
+
#SIGNALS = [ :QUIT, :INT, :TERM ]
|
13
|
+
|
14
|
+
DOUBLE_PROCESS_CHECK__OK = 1
|
15
|
+
DOUBLE_PROCESS_CHECK__AUTO_RECOVERD = 2
|
16
|
+
DOUBLE_PROCESS_CHECK__NG = 0
|
17
|
+
DOUBLE_PROCESS_CHECK__STILL_RUNNING = -1
|
18
|
+
|
19
|
+
def option_parser
|
20
|
+
@__option_parser ||= OptionParser.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_option_parser(v)
|
24
|
+
@__option_parser = v
|
25
|
+
end
|
26
|
+
|
27
|
+
def env
|
28
|
+
@__env ||= {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def executed
|
32
|
+
@__executed
|
33
|
+
end
|
34
|
+
|
35
|
+
def pg_path;env[:pg_path];end
|
36
|
+
|
37
|
+
def pid_file;env[:pid_file];end
|
38
|
+
|
39
|
+
#
|
40
|
+
# loggerの出力をOFFにしたい場合は
|
41
|
+
# 引数を"/dev/null"で渡してください
|
42
|
+
#
|
43
|
+
def logger
|
44
|
+
@__logger ||= create_logger
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# 内部保持をするロガーを新規作成
|
49
|
+
#
|
50
|
+
def create_logger(io=STDERR,log_level=Logger::INFO)
|
51
|
+
@__logger = Logger.new(io)
|
52
|
+
@__logger.formatter = Kanamei::LogFormatter.formatter
|
53
|
+
@__logger.level = log_level
|
54
|
+
@__logger
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# 内部保持するロガーを引数にて設定
|
59
|
+
#
|
60
|
+
def set_logger(_logger)
|
61
|
+
@__logger = _logger
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# ログを出力しないように設定(内部的にはログを出力するが、その向き先が/dev/nullって実装になってます)
|
66
|
+
#
|
67
|
+
def skip_logging
|
68
|
+
create_logger("/dev/null")
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# 内部的には
|
73
|
+
# init
|
74
|
+
# parse_options
|
75
|
+
# execute_inner
|
76
|
+
# release
|
77
|
+
# の順にコールしてます
|
78
|
+
#
|
79
|
+
# [options]
|
80
|
+
# プログラムより指定するバッチ動作オプション(ハッシュ値)
|
81
|
+
# :double_process_check 初期値 true
|
82
|
+
# :auto_recover 初期値 false
|
83
|
+
#
|
84
|
+
def execute(options={},&process)
|
85
|
+
begin
|
86
|
+
init
|
87
|
+
logger.info "start script(#{pg_path})"
|
88
|
+
logger.debug "caller=#{caller}"
|
89
|
+
parse_options(options,ARGV)
|
90
|
+
result = double_process_check_and_create_pid_file
|
91
|
+
case result
|
92
|
+
when DOUBLE_PROCESS_CHECK__OK,DOUBLE_PROCESS_CHECK__AUTO_RECOVERD
|
93
|
+
if result == DOUBLE_PROCESS_CHECK__AUTO_RECOVERD
|
94
|
+
logger.warn "lock file still exists[pid=#{env[:old_pid_from_pid_file]}:file=#{pid_file}],but process does not found.Auto_recover enabled.so process continues"
|
95
|
+
end
|
96
|
+
execute_inner(&process)
|
97
|
+
when DOUBLE_PROCESS_CHECK__NG
|
98
|
+
logger.error "lock file still exists[pid=#{env[:old_pid_from_pid_file]}:file=#{pid_file}],but process does not found.Auto_recover disabled.so process can not continue"
|
99
|
+
when DOUBLE_PROCESS_CHECK__STILL_RUNNING
|
100
|
+
logger.warn "pid:#{env[:old_pid_from_pid_file]} still running"
|
101
|
+
else
|
102
|
+
raise 'must not happen'
|
103
|
+
end
|
104
|
+
rescue => e
|
105
|
+
logger.error e
|
106
|
+
ensure
|
107
|
+
release
|
108
|
+
logger.info "finish script (%1.3fsec)" % (Time.now - @__script_started_at)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
module ClassMethods
|
113
|
+
def is_there_process(pid)
|
114
|
+
pid = pid.to_i
|
115
|
+
raise 'pid must be number' if pid == 0
|
116
|
+
process = Sys::ProcTable.ps(pid)
|
117
|
+
process != nil && process.state == 'run'
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.included(mod)
|
122
|
+
# ModuleのインスタンスmodがAをincludeした際に呼び出され、
|
123
|
+
# A::ClassMethodsのインスタンスメソッドをmodに特異メソッドとして追加する。
|
124
|
+
mod.extend ClassMethods
|
125
|
+
end
|
126
|
+
|
127
|
+
def signal_observers
|
128
|
+
@__signal_observers ||= []
|
129
|
+
end
|
130
|
+
|
131
|
+
def set_signal_observer(method_name)
|
132
|
+
@__signal_observers ||= []
|
133
|
+
case method_name
|
134
|
+
when String
|
135
|
+
method_name = method_name.to_sym
|
136
|
+
when Symbol
|
137
|
+
else
|
138
|
+
raise ArgumentError.new('method_name must be String or Symbol')
|
139
|
+
end
|
140
|
+
@__signal_observers << method_name
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
def init
|
146
|
+
SIGNALS.each { |sig| trap(sig){r_signal(sig)} }
|
147
|
+
@__script_started_at = Time.now
|
148
|
+
raise 'already inited' if @__init
|
149
|
+
@__init = true
|
150
|
+
env[:pid] = $$
|
151
|
+
if File.expand_path(caller[0]) =~ /(.*):\d*:in `.*?'\z/
|
152
|
+
env[:pg_path] = $1
|
153
|
+
else
|
154
|
+
raise "must not happen!! can not get caller value"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def parse_options(options,argv)
|
159
|
+
env[:double_process_check] = options[:double_process_check]
|
160
|
+
env[:double_process_check] = true if env[:double_process_check] == nil
|
161
|
+
env[:auto_recover] = options[:auto_recover]
|
162
|
+
env[:auto_recover] = false if env[:auto_recover] == nil
|
163
|
+
env[:environment] = options[:environment] ||= 'development'
|
164
|
+
env[:pg_name] = File.basename(pg_path)
|
165
|
+
env[:pid_file] = options[:pid_file]
|
166
|
+
env[:daemonize] = options[:daemonize]
|
167
|
+
env[:daemonize] = false if env[:daemonize] == nil
|
168
|
+
env[:pid_file] ||= "/tmp/.#{env[:pg_name]}.#{Digest::MD5.hexdigest(pg_path)}.pid"
|
169
|
+
|
170
|
+
opts = option_parser
|
171
|
+
|
172
|
+
opts.on("-e", "--environment=name",
|
173
|
+
String,"specifies the environment",
|
174
|
+
"default: development") do |v|
|
175
|
+
env[:environment] = v
|
176
|
+
end
|
177
|
+
|
178
|
+
opts.on("-d", "--daemonize") do
|
179
|
+
env[:daemonize] = true
|
180
|
+
end
|
181
|
+
|
182
|
+
opts.on("-h","--help","show this help message.") { $stderr.puts opts; exit }
|
183
|
+
|
184
|
+
opts.on("--lockfile LOCK_FILE_PATH","set lock file path") do |v|
|
185
|
+
double_process_check = true
|
186
|
+
env[:pid_file] = v
|
187
|
+
end
|
188
|
+
opts.on("--double_process_check_off","disable double process check") do |v|
|
189
|
+
env[:double_process_check] = false
|
190
|
+
end
|
191
|
+
opts.on("--auto_recover","enable auto recover mode") do |v|
|
192
|
+
env[:auto_recover] = true
|
193
|
+
end
|
194
|
+
|
195
|
+
opts.parse!(argv)
|
196
|
+
|
197
|
+
if env[:auto_recover] == true
|
198
|
+
env[:double_process_check] = true
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def double_process_check_and_create_pid_file
|
203
|
+
ret = DOUBLE_PROCESS_CHECK__OK
|
204
|
+
if env[:double_process_check]
|
205
|
+
double_process_check_worked = false
|
206
|
+
#pg_path = File.expand_path($0)
|
207
|
+
logger.debug pid_file
|
208
|
+
if File.exists?(pid_file)
|
209
|
+
pid = File.open(pid_file).read.chomp
|
210
|
+
env[:old_pid_from_pid_file] = pid
|
211
|
+
if (pid != nil && pid != "" ) && self.class.is_there_process(pid)
|
212
|
+
env[:double_process_check_problem] = true
|
213
|
+
return DOUBLE_PROCESS_CHECK__STILL_RUNNING
|
214
|
+
else
|
215
|
+
if env[:auto_recover]
|
216
|
+
ret = DOUBLE_PROCESS_CHECK__AUTO_RECOVERD
|
217
|
+
else
|
218
|
+
env[:double_process_check_problem] = true
|
219
|
+
return DOUBLE_PROCESS_CHECK__NG
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
File.open(pid_file, "w"){|f|f.write $$}
|
224
|
+
env[:double_process_check_worked] = double_process_check_worked
|
225
|
+
end
|
226
|
+
ret
|
227
|
+
end
|
228
|
+
|
229
|
+
def release
|
230
|
+
# 2重起動チェックで問題があった場合はpid_fileを消してはいけないので
|
231
|
+
unless env[:double_process_check_problem]
|
232
|
+
File.delete(pid_file) if pid_file && File.exist?(pid_file)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
#
|
237
|
+
# receive_signal
|
238
|
+
# 一応名前がバッティングしないように、、
|
239
|
+
#
|
240
|
+
def r_signal(signal)
|
241
|
+
sent_signal = false
|
242
|
+
signal_observers.each do |method_name|
|
243
|
+
begin
|
244
|
+
self.send method_name,signal
|
245
|
+
sent_signal = true
|
246
|
+
rescue => e
|
247
|
+
message = "signal #{signal} received. but can not call '#{method_name}'"
|
248
|
+
env[:signal_error] = message
|
249
|
+
logger.error(message)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
unless sent_signal
|
254
|
+
trap(signal,"DEFAULT")
|
255
|
+
Process.kill signal,$$
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def execute_inner(&process)
|
260
|
+
@__executed = true
|
261
|
+
if env[:daemonize]
|
262
|
+
# HACKME logging
|
263
|
+
logger.info "daemonized"
|
264
|
+
env[:pid_old] = env[:pid]
|
265
|
+
Process.daemon
|
266
|
+
env[:pid] = Process.pid
|
267
|
+
File.open(pid_file, "w"){|f|f.write env[:pid]}
|
268
|
+
sleep 1
|
269
|
+
end
|
270
|
+
return yield(process)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
data/lib/batchbase.rb
ADDED
data/readme.md
ADDED
data/test/batch.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
class Batch
|
2
|
+
include Batchbase::Core
|
3
|
+
skip_logging
|
4
|
+
|
5
|
+
TEST_FILE = '/tmp/.batchbase_batch.txt'
|
6
|
+
|
7
|
+
def proceed(opt={})
|
8
|
+
@shutdown = false
|
9
|
+
set_signal_observer(:receive_signal)
|
10
|
+
|
11
|
+
execute(opt) do
|
12
|
+
sleep 2
|
13
|
+
File.write(TEST_FILE,$$)
|
14
|
+
if opt[:daemonize]
|
15
|
+
loop do
|
16
|
+
sleep 1
|
17
|
+
if @shutdown
|
18
|
+
#puts "shutdown by #{@shutdown}"
|
19
|
+
break
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
11
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def receive_signal(sig)
|
28
|
+
@shutdown = sig
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class BatchTooLong
|
2
|
+
include Batchbase::Core
|
3
|
+
|
4
|
+
def proceed(opt={})
|
5
|
+
unless opt[:not_set_observer]
|
6
|
+
if opt[:signal_cancel]
|
7
|
+
set_signal_observer(:ignore_signal)
|
8
|
+
else
|
9
|
+
set_signal_observer(:receive_signal)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
@shutdown = false
|
13
|
+
execute(opt) do
|
14
|
+
100.times do
|
15
|
+
sleep 1
|
16
|
+
break if @shutdown
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def receive_signal(sig)
|
22
|
+
@shutdown = true
|
23
|
+
end
|
24
|
+
|
25
|
+
def ignore_signal(sig)
|
26
|
+
end
|
27
|
+
end
|
data/test/by_hand.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
# -*- coding: utf-8 -*-
|
4
|
+
|
5
|
+
$: << File.dirname(__FILE__)
|
6
|
+
require 'test_helper'
|
7
|
+
|
8
|
+
require 'batch'
|
9
|
+
require 'logger'
|
10
|
+
|
11
|
+
class CheckLogger
|
12
|
+
def self.check
|
13
|
+
logger = Logger.new(STDERR)
|
14
|
+
logger.formatter = Batchbase::LogFormatter.formatter
|
15
|
+
logger.info 'test'
|
16
|
+
logger.info 1
|
17
|
+
begin
|
18
|
+
raise 'some error'
|
19
|
+
rescue => e
|
20
|
+
logger.error e
|
21
|
+
end
|
22
|
+
|
23
|
+
logger = Logger.new("/dev/null")
|
24
|
+
logger.formatter = Batchbase::LogFormatter.formatter
|
25
|
+
logger.info 'should not show'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
CheckLogger.check
|
30
|
+
|
31
|
+
|
data/test/test.rb
ADDED
@@ -0,0 +1,321 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
$: << File.dirname(__FILE__)
|
4
|
+
require 'test_helper'
|
5
|
+
require 'test/unit'
|
6
|
+
require 'Fileutils'
|
7
|
+
|
8
|
+
#require 'bundler'
|
9
|
+
#Bundler.require
|
10
|
+
|
11
|
+
#require 'sys/proctable'
|
12
|
+
|
13
|
+
require 'batch'
|
14
|
+
require 'batch_too_long'
|
15
|
+
|
16
|
+
class TestBatchbase < Test::Unit::TestCase
|
17
|
+
|
18
|
+
PID_FILE_FORCE = '/tmp/.batchbase_test.pid'
|
19
|
+
PID_FILE_DAEMONIZE_TEST = '/tmp/.batchbase_daemonize_test.pid'
|
20
|
+
|
21
|
+
def setup
|
22
|
+
delete_file(pid_file)
|
23
|
+
delete_file(PID_FILE_FORCE)
|
24
|
+
delete_file(PID_FILE_DAEMONIZE_TEST)
|
25
|
+
delete_file(Batch::TEST_FILE)
|
26
|
+
end
|
27
|
+
|
28
|
+
def new_batch_instance
|
29
|
+
b = Batch.new
|
30
|
+
b.skip_logging
|
31
|
+
b
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete_file(file)
|
35
|
+
File.delete(file) if File.exist?(file)
|
36
|
+
end
|
37
|
+
|
38
|
+
def pid_file
|
39
|
+
b = new_batch_instance
|
40
|
+
b.send(:init)
|
41
|
+
b.send(:parse_options,{},[])
|
42
|
+
b.env[:pid_file]
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_pid_file
|
46
|
+
b = new_batch_instance
|
47
|
+
b.send(:init)
|
48
|
+
b.send(:parse_options,{},[])
|
49
|
+
b.send(:double_process_check_and_create_pid_file)
|
50
|
+
assert_equal true,File.exists?(b.env[:pid_file])
|
51
|
+
b.send(:release)
|
52
|
+
assert_equal false,File.exists?(b.env[:pid_file])
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_there_was_lock_file
|
56
|
+
FileUtils.touch(pid_file) # すでにpid_fileがあるとして
|
57
|
+
b = new_batch_instance
|
58
|
+
b.send(:init)
|
59
|
+
b.send(:parse_options,{},[])
|
60
|
+
result = b.send(:double_process_check_and_create_pid_file)
|
61
|
+
assert_equal Batchbase::Core::DOUBLE_PROCESS_CHECK__NG,result
|
62
|
+
File.delete(pid_file)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_there_was_lock_file_but_not_double_cheking
|
66
|
+
FileUtils.touch(pid_file) # すでにpid_fileがあるとして
|
67
|
+
b = new_batch_instance
|
68
|
+
b.send(:init)
|
69
|
+
b.send(:parse_options,{:double_process_check=>false},[])
|
70
|
+
result = b.send(:double_process_check_and_create_pid_file)
|
71
|
+
assert_equal Batchbase::Core::DOUBLE_PROCESS_CHECK__OK,result
|
72
|
+
File.delete(pid_file)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_auto_recover
|
76
|
+
FileUtils.touch(pid_file) # すでにpid_fileがあるとして
|
77
|
+
b = new_batch_instance
|
78
|
+
b.send(:init)
|
79
|
+
b.send(:parse_options,{:auto_recover=>true},[])
|
80
|
+
result = b.send(:double_process_check_and_create_pid_file)
|
81
|
+
assert_equal Batchbase::Core::DOUBLE_PROCESS_CHECK__AUTO_RECOVER,result
|
82
|
+
assert_equal true,File.exists?(b.env[:pid_file]) # pid_fileは存在していないとだめ
|
83
|
+
File.delete(pid_file)
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_auto_recover
|
87
|
+
b = new_batch_instance
|
88
|
+
b.send(:init)
|
89
|
+
b.send(:parse_options,{},[:auto_recover=>true])
|
90
|
+
b.send(:double_process_check_and_create_pid_file)
|
91
|
+
assert_equal true,File.exists?(b.env[:pid_file])
|
92
|
+
b.send(:release)
|
93
|
+
assert_equal false,File.exists?(b.env[:pid_file])
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_option_parser
|
97
|
+
# ぎゃくにかいてもーた、、、、
|
98
|
+
b = new_batch_instance
|
99
|
+
b.send(:init)
|
100
|
+
argv = []
|
101
|
+
b.send(:parse_options,{},argv)
|
102
|
+
assert_equal b.env[:environment],'development'
|
103
|
+
assert_equal b.env[:double_process_check],true
|
104
|
+
assert_equal b.env[:auto_recover],false
|
105
|
+
assert_equal b.env[:pg_name],'test.rb'
|
106
|
+
|
107
|
+
b = new_batch_instance
|
108
|
+
b.send(:init)
|
109
|
+
argv = ['-e','test','--auto_recover']
|
110
|
+
b.send(:parse_options,{},argv)
|
111
|
+
assert_equal b.env[:environment],'test'
|
112
|
+
assert_equal b.env[:double_process_check],true
|
113
|
+
assert_equal b.env[:auto_recover],true
|
114
|
+
|
115
|
+
b = new_batch_instance
|
116
|
+
b.send(:init)
|
117
|
+
argv = ['--double_process_check_off']
|
118
|
+
b.send(:parse_options,{},argv)
|
119
|
+
assert_equal b.env[:double_process_check],false
|
120
|
+
|
121
|
+
# オートリカバリー入れたらダブルプロセスチェックは強制ON
|
122
|
+
b = new_batch_instance
|
123
|
+
b.send(:init)
|
124
|
+
argv = ['-e','test','--auto_recover','double_process_check_off']
|
125
|
+
b.send(:parse_options,{},argv)
|
126
|
+
assert_equal b.env[:environment],'test'
|
127
|
+
assert_equal b.env[:double_process_check],true
|
128
|
+
assert_equal b.env[:auto_recover],true
|
129
|
+
|
130
|
+
b = new_batch_instance
|
131
|
+
b.send(:init)
|
132
|
+
argv = ['--lockfile','/tmp/.lockfile_test']
|
133
|
+
b.send(:parse_options,{},argv)
|
134
|
+
assert_equal b.env[:pid_file],'/tmp/.lockfile_test'
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_options
|
138
|
+
# ぎゃくにかいてもーた、、、、
|
139
|
+
b = new_batch_instance
|
140
|
+
b.send(:init)
|
141
|
+
argv = []
|
142
|
+
options = {:double_process_check=>false,:environment=>'test'}
|
143
|
+
b.send(:parse_options,options,argv)
|
144
|
+
assert_equal b.env[:environment],'test'
|
145
|
+
assert_equal b.env[:double_process_check],false
|
146
|
+
assert_equal b.env[:auto_recover],false
|
147
|
+
assert_equal b.env[:pg_name],'test.rb'
|
148
|
+
|
149
|
+
# オートリカバリー入れたらダブルプロセスチェックは強制ON
|
150
|
+
b = new_batch_instance
|
151
|
+
b.send(:init)
|
152
|
+
argv = []
|
153
|
+
options = {:double_process_check=>false,:auto_recover=>true}
|
154
|
+
b.send(:parse_options,options,argv)
|
155
|
+
assert_equal b.env[:double_process_check],true
|
156
|
+
assert_equal b.env[:auto_recover],true
|
157
|
+
|
158
|
+
b = new_batch_instance
|
159
|
+
b.send(:init)
|
160
|
+
argv = []
|
161
|
+
options = {:pid_file=>'/tmp/.lock_test'}
|
162
|
+
b.send(:parse_options,options,argv)
|
163
|
+
assert_equal b.env[:pid_file],'/tmp/.lock_test'
|
164
|
+
|
165
|
+
# ミックスならARGVの指定の方を優先
|
166
|
+
b = new_batch_instance
|
167
|
+
b.send(:init)
|
168
|
+
argv = ['--lockfile','/tmp/.lllock','--auto_recover']
|
169
|
+
options = {:pid_file=>'/tmp/.lock_test',:auto_recover=>false,:double_process_check=>false}
|
170
|
+
b.send(:parse_options,options,argv)
|
171
|
+
assert_equal b.env[:double_process_check],true
|
172
|
+
assert_equal b.env[:auto_recover],true
|
173
|
+
assert_equal b.env[:pid_file],'/tmp/.lllock'
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_options_plus
|
177
|
+
b = new_batch_instance
|
178
|
+
opts = b.option_parser
|
179
|
+
opts.on("-f", "--favorite_number=value",
|
180
|
+
Integer,"your favorite number"
|
181
|
+
) do |v|
|
182
|
+
b.env[:favorite_number] = v
|
183
|
+
end
|
184
|
+
|
185
|
+
b.send(:init)
|
186
|
+
argv = ['--favorite_number','11']
|
187
|
+
b.send(:parse_options,{},argv)
|
188
|
+
assert_equal 'development',b.env[:environment]
|
189
|
+
assert_equal true,b.env[:double_process_check]
|
190
|
+
assert_equal false,b.env[:auto_recover]
|
191
|
+
assert_equal 'test.rb',b.env[:pg_name]
|
192
|
+
assert_equal 11,b.env[:favorite_number]
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_daemonize
|
196
|
+
pid = fork do
|
197
|
+
b = new_batch_instance
|
198
|
+
b.proceed(:daemonize=>true,:pid_file=>PID_FILE_DAEMONIZE_TEST)
|
199
|
+
end
|
200
|
+
|
201
|
+
sleep 1
|
202
|
+
#
|
203
|
+
# デーモン化すると
|
204
|
+
# ・pidが変わる
|
205
|
+
# ・ppidが1になるk
|
206
|
+
#
|
207
|
+
pid_new = File.read(PID_FILE_DAEMONIZE_TEST).chomp.to_i
|
208
|
+
assert_not_equal pid,pid_new
|
209
|
+
daemon_process = Sys::ProcTable.ps(pid_new)
|
210
|
+
assert_equal 1,daemon_process.ppid
|
211
|
+
sleep 3
|
212
|
+
assert_equal true,Batch.is_there_process(pid_new)
|
213
|
+
# デーモン化したスクリプトから書き込んだ自身のpidがこちらで認識しているpidと同一化の確認
|
214
|
+
assert_equal pid_new,File.read(Batch::TEST_FILE).chomp.to_i
|
215
|
+
# シグナルを送る
|
216
|
+
# pid_fileを消して終了するか?
|
217
|
+
`kill #{pid_new}`
|
218
|
+
sleep 3
|
219
|
+
assert_equal false,Batch.is_there_process(pid_new)
|
220
|
+
assert_equal false,File.exists?(PID_FILE_DAEMONIZE_TEST)
|
221
|
+
end
|
222
|
+
|
223
|
+
def test_is_there_process
|
224
|
+
assert_equal true,Batch.is_there_process($$)
|
225
|
+
assert_equal false,Batch.is_there_process(1111111111)
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_signal
|
229
|
+
assert_equal false,File.exists?(PID_FILE_FORCE)
|
230
|
+
pid = fork do
|
231
|
+
b = BatchTooLong.new
|
232
|
+
b.skip_logging
|
233
|
+
b.proceed(:pid_file=>PID_FILE_FORCE)
|
234
|
+
end
|
235
|
+
sleep 3
|
236
|
+
pid_by_file = File.read(PID_FILE_FORCE).chomp.to_i
|
237
|
+
assert_equal true,Batch.is_there_process(pid)
|
238
|
+
assert_equal pid,pid_by_file
|
239
|
+
# シグナルを送る
|
240
|
+
# pid_fileを消して終了するか?
|
241
|
+
`kill #{pid}`
|
242
|
+
sleep 3
|
243
|
+
assert_equal false,Batch.is_there_process(pid)
|
244
|
+
assert_equal false,File.exists?(PID_FILE_FORCE)
|
245
|
+
end
|
246
|
+
|
247
|
+
#
|
248
|
+
# オブザーバーを設定していない場合は
|
249
|
+
# デフォルトの挙動をするように変更して
|
250
|
+
# もう一度同様のシグナルを受ける
|
251
|
+
#
|
252
|
+
def test_signal_observer_not_set
|
253
|
+
assert_equal false,File.exists?(PID_FILE_FORCE)
|
254
|
+
pid = fork do
|
255
|
+
b = BatchTooLong.new
|
256
|
+
b.skip_logging
|
257
|
+
b.proceed(:pid_file=>PID_FILE_FORCE,:not_set_observer=>true)
|
258
|
+
end
|
259
|
+
sleep 3
|
260
|
+
pid_by_file = File.read(PID_FILE_FORCE).chomp.to_i
|
261
|
+
assert_equal true,Batch.is_there_process(pid)
|
262
|
+
assert_equal pid,pid_by_file
|
263
|
+
`kill #{pid}`
|
264
|
+
sleep 3
|
265
|
+
# 普通に終了すべき
|
266
|
+
assert_equal false,Batch.is_there_process(pid)
|
267
|
+
assert_equal false,File.exists?(PID_FILE_FORCE)
|
268
|
+
end
|
269
|
+
|
270
|
+
# 特に何もしないシグナルハンドラーを設定すると
|
271
|
+
def test_signal_ignore
|
272
|
+
assert_equal false,File.exists?(PID_FILE_FORCE)
|
273
|
+
pid = fork do
|
274
|
+
b = BatchTooLong.new
|
275
|
+
b.skip_logging
|
276
|
+
b.proceed(:pid_file=>PID_FILE_FORCE,:signal_cancel=>true)
|
277
|
+
end
|
278
|
+
sleep 3
|
279
|
+
pid_by_file = File.read(PID_FILE_FORCE).chomp.to_i
|
280
|
+
assert_equal true,Batch.is_there_process(pid)
|
281
|
+
assert_equal pid,pid_by_file
|
282
|
+
`kill #{pid}`
|
283
|
+
sleep 3
|
284
|
+
# 終了しない
|
285
|
+
assert_equal true,Batch.is_there_process(pid)
|
286
|
+
assert_equal true,File.exists?(PID_FILE_FORCE)
|
287
|
+
`kill -9 #{pid}`
|
288
|
+
sleep 3
|
289
|
+
# 終了するがpidファイルは残る
|
290
|
+
assert_equal false,Batch.is_there_process(pid)
|
291
|
+
assert_equal true,File.exists?(PID_FILE_FORCE)
|
292
|
+
end
|
293
|
+
|
294
|
+
# すでにバッチ起動&プロセスがまだ存在する場合のテスト
|
295
|
+
def test_prosess_still_exists
|
296
|
+
pid = fork do
|
297
|
+
b = new_batch_instance
|
298
|
+
b.proceed(:pid_file=>PID_FILE_FORCE)
|
299
|
+
end
|
300
|
+
|
301
|
+
sleep 1
|
302
|
+
|
303
|
+
b2 = new_batch_instance
|
304
|
+
b2.send(:init)
|
305
|
+
b2.send(:parse_options,{:pid_file=>PID_FILE_FORCE},[])
|
306
|
+
result = b2.send(:double_process_check_and_create_pid_file)
|
307
|
+
assert_equal Batch::DOUBLE_PROCESS_CHECK__STILL_RUNNING,result
|
308
|
+
#b2.send(:execute_inner)
|
309
|
+
b2.send(:release)
|
310
|
+
# pid_fileまだは存在していないとだめ
|
311
|
+
assert_equal true,File.exists?(b2.env[:pid_file])
|
312
|
+
sleep 2
|
313
|
+
end
|
314
|
+
|
315
|
+
#
|
316
|
+
# HACKME
|
317
|
+
# executeを読んだ際のメッセージ文言等でエラーが出る場合のフック、、、
|
318
|
+
# 実際はexecuteをシュミレートしたテストしかしていない&log出力も
|
319
|
+
# 切ってるので、、、、、、
|
320
|
+
#
|
321
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: batchbase
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- pacojp
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sys-proctable
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - '='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.9.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - '='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.9.1
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: kanamei_log_formatter
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - '='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.0.1
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - '='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.0.1
|
46
|
+
description: oreore batch base class
|
47
|
+
email:
|
48
|
+
- paco.jp@gmail.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- .gitignore
|
54
|
+
- Gemfile
|
55
|
+
- Rakefile
|
56
|
+
- batchbase.gemspec
|
57
|
+
- example/sample1.rb
|
58
|
+
- example/sample2.rb
|
59
|
+
- example/sample3.rb
|
60
|
+
- lib/batchbase.rb
|
61
|
+
- lib/batchbase/core.rb
|
62
|
+
- lib/batchbase/version.rb
|
63
|
+
- readme.md
|
64
|
+
- test/batch.rb
|
65
|
+
- test/batch_too_long.rb
|
66
|
+
- test/by_hand.rb
|
67
|
+
- test/check_logger.rb
|
68
|
+
- test/test.rb
|
69
|
+
- test/test_helper.rb
|
70
|
+
homepage: ''
|
71
|
+
licenses: []
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ! '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
requirements: []
|
89
|
+
rubyforge_project: batchbase
|
90
|
+
rubygems_version: 1.8.23
|
91
|
+
signing_key:
|
92
|
+
specification_version: 3
|
93
|
+
summary: oreore batch base class
|
94
|
+
test_files:
|
95
|
+
- test/batch.rb
|
96
|
+
- test/batch_too_long.rb
|
97
|
+
- test/by_hand.rb
|
98
|
+
- test/check_logger.rb
|
99
|
+
- test/test.rb
|
100
|
+
- test/test_helper.rb
|
101
|
+
has_rdoc:
|