rerun_task 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +32 -0
- data/Rakefile +1 -0
- data/bin/rerun_task_crontab.rb +3 -0
- data/config/rerun_task.yml +1 -0
- data/lib/rerun_task/config.rb +4 -0
- data/lib/rerun_task/crontab.rb +16 -0
- data/lib/rerun_task/pids.rb +22 -0
- data/lib/rerun_task/process_file.rb +79 -0
- data/lib/rerun_task/unfinished_runner.rb +14 -0
- data/lib/rerun_task/version.rb +3 -0
- data/lib/rerun_task/watch_process.rb +25 -0
- data/lib/rerun_task.rb +11 -0
- data/rerun_task.gemspec +23 -0
- data/test/watch_process_test.rb +70 -0
- metadata +92 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
Rerun Task
|
2
|
+
==========
|
3
|
+
|
4
|
+
|
5
|
+
Rerun task is gem for checking if your rake task was executed successfully. You have to place all your rake code to `WatchProcess.new("task_name").call{}`. I write below some examples.
|
6
|
+
|
7
|
+
Examples
|
8
|
+
====
|
9
|
+
task :dummy_task => :environment do
|
10
|
+
WatchProcess.new("task_name").call do
|
11
|
+
# your code write here
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Now if you run rake task, then is created pid-files of your process. To your crontab place task, which every 5th minute check if all task done successfully.
|
16
|
+
|
17
|
+
non-rails app
|
18
|
+
====
|
19
|
+
If you use as non-rails app, you have to copy /bin/rerun_task_crontab.rb from gem to your app
|
20
|
+
|
21
|
+
*/5 * * * * ruby /path/to/the/your-app/bin/rerun_task_crontab.rb
|
22
|
+
|
23
|
+
rails app
|
24
|
+
====
|
25
|
+
|
26
|
+
If you use it in rails app, you can use rails runner
|
27
|
+
|
28
|
+
*/5 * * * * cd path/to/your-app; bundle exec rails runner RerunTask::UnfinishedRunner.crontab_retry
|
29
|
+
|
30
|
+
Notes
|
31
|
+
====
|
32
|
+
In this version is not allowed to run same process in same time.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1 @@
|
|
1
|
+
pid_dir: "/tmp"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module RerunTask
|
2
|
+
class Crontab
|
3
|
+
attr_accessor :content
|
4
|
+
def initialize
|
5
|
+
@content = %x[crontab -l]
|
6
|
+
@content = @content.split("\n")
|
7
|
+
end
|
8
|
+
|
9
|
+
def find_task(task_name)
|
10
|
+
match = @content.reject{|i| !i.include?(task_name)}
|
11
|
+
return nil if match.size == 0
|
12
|
+
match.first.split(" ")[5,9].join(" ")
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module RerunTask
|
2
|
+
class Pids
|
3
|
+
def self.unfinished
|
4
|
+
res = []
|
5
|
+
Dir.glob("#{RerunTask::CONFIG['pid_dir']}/rerun_task/pids/*.pid").each do |file_path|
|
6
|
+
args = {}
|
7
|
+
File.open(file_path, 'r') do |f|
|
8
|
+
args = ProcessFile.parse_file(f.read)
|
9
|
+
end
|
10
|
+
next if args[:process_name].nil? || args[:pid].nil?
|
11
|
+
p = ProcessFile.load_file("#{RerunTask::CONFIG['pid_dir']}/rerun_task/pids", args[:process_name])
|
12
|
+
begin
|
13
|
+
p.process_exists?
|
14
|
+
rescue
|
15
|
+
res << p
|
16
|
+
next
|
17
|
+
end
|
18
|
+
end
|
19
|
+
res
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module RerunTask
|
4
|
+
class ProcessFile
|
5
|
+
attr_accessor :process_name, :pid
|
6
|
+
|
7
|
+
def initialize(pid_dir)
|
8
|
+
@pid_dir = pid_dir
|
9
|
+
FileUtils.mkdir_p(@pid_dir) unless Dir.exists?(@pid_dir)
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_pid_file
|
13
|
+
if File.exists?(path)
|
14
|
+
puts "file exists #{path}"
|
15
|
+
|
16
|
+
process_from_file = ProcessFile.load_file(@pid_dir, process_name)
|
17
|
+
raise RuntimeError.new("Process #{process_name} is already running with pid #{process_from_file.pid}") if process_from_file.process_exists?
|
18
|
+
end
|
19
|
+
|
20
|
+
File.open(path, 'w+') do |f|
|
21
|
+
f.write(self.to_s)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def path
|
26
|
+
ProcessFile.create_file_path(@pid_dir, process_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.create_file_path(pid_dir, process_name)
|
30
|
+
basename = Pathname.new("#{pid_dir}/#{process_name}.pid").basename
|
31
|
+
"#{pid_dir}/#{basename}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def process_name
|
35
|
+
@process_name = @process_name || extract_process_name(Process.pid)
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_s
|
39
|
+
"#{Process.pid}\n#{process_name}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def process_exists?
|
43
|
+
extract_process_name(pid) == @process_name
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.load_file(pid_dir, process_name)
|
47
|
+
f = File.open(create_file_path(pid_dir, process_name), 'r')
|
48
|
+
p = ProcessFile.new(pid_dir)
|
49
|
+
args = parse_file(f.read)
|
50
|
+
p.process_name = process_name.nil? ? args[:process_name] : process_name
|
51
|
+
p.pid = args[:pid]
|
52
|
+
f.close
|
53
|
+
p
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.parse_file(string)
|
57
|
+
a = string.split("\n")
|
58
|
+
{ pid: a.first, process_name: a.last }
|
59
|
+
end
|
60
|
+
|
61
|
+
def destroy
|
62
|
+
FileUtils.rm(path)
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def extract_process_name(pid)
|
68
|
+
ps_res = %x[ps ax]
|
69
|
+
ps_res = ps_res.split("\n")
|
70
|
+
name = ""
|
71
|
+
ps_res.each do |line|
|
72
|
+
rows = line.split(" ")
|
73
|
+
name = rows.last if rows.first == pid.to_s
|
74
|
+
end
|
75
|
+
raise RuntimeError.new("process_name not found for pid #{pid}") if name === ""
|
76
|
+
name
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module RerunTask
|
2
|
+
class UnfinishedRunner
|
3
|
+
|
4
|
+
def self.crontab_retry
|
5
|
+
crontab = Crontab.new()
|
6
|
+
Pids.unfinished.each do |process_file|
|
7
|
+
cmd = crontab.find_task(process_file.process_name)
|
8
|
+
next if cmd.nil?
|
9
|
+
puts "Running command #{cmd} again"
|
10
|
+
system("#{cmd} &")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RerunTask
|
2
|
+
class WatchProcess
|
3
|
+
|
4
|
+
def initialize(rake_task_name)
|
5
|
+
@name = rake_task_name
|
6
|
+
@pid_dir = "#{RerunTask::CONFIG['pid_dir']}/rerun_task/pids"
|
7
|
+
@process_file = ProcessFile.new(@pid_dir)
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(&block)
|
11
|
+
start
|
12
|
+
block.call
|
13
|
+
finished
|
14
|
+
end
|
15
|
+
|
16
|
+
def start
|
17
|
+
@process_file.create_pid_file
|
18
|
+
end
|
19
|
+
|
20
|
+
def finished
|
21
|
+
@process_file.destroy
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
data/lib/rerun_task.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require "rerun_task/version"
|
2
|
+
require "rerun_task/config"
|
3
|
+
require "rerun_task/watch_process"
|
4
|
+
require "rerun_task/process_file"
|
5
|
+
require "rerun_task/pids"
|
6
|
+
require "rerun_task/crontab"
|
7
|
+
require "rerun_task/unfinished_runner"
|
8
|
+
|
9
|
+
module RerunTask
|
10
|
+
|
11
|
+
end
|
data/rerun_task.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "rerun_task/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "rerun_task"
|
7
|
+
s.version = RerunTask::VERSION
|
8
|
+
s.authors = ["lukasvotypka"]
|
9
|
+
s.email = ["lukas.votypka@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Re-run task if is not finished}
|
12
|
+
s.description = %q{This gem is developed for handling rake task and re-run them if didn't finished successfully}
|
13
|
+
|
14
|
+
s.rubyforge_project = "rerun_task"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency "test-unit"
|
22
|
+
s.add_development_dependency "mocha"
|
23
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require "mocha/setup"
|
3
|
+
require 'rerun_task'
|
4
|
+
|
5
|
+
class WatchProcessTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
# Called before every test method runs. Can be used
|
8
|
+
# to set up fixture information.
|
9
|
+
def setup
|
10
|
+
@process_file = RerunTask::ProcessFile.new("#{RerunTask::CONFIG['pid_dir']}/rerun_task/pids")
|
11
|
+
begin
|
12
|
+
FileUtils.rm(@process_file.path)
|
13
|
+
rescue
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Called after every test method runs. Can be used to tear
|
18
|
+
# down fixture information.
|
19
|
+
|
20
|
+
def teardown
|
21
|
+
# Do nothing
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_should_start
|
25
|
+
#assert_equal("/tmp/rerun_task/pids/watch_process_test.rb.pid", @process_file.path)
|
26
|
+
@w = RerunTask::WatchProcess.new("my_test")
|
27
|
+
assert_equal(false, File.exists?(@process_file.path))
|
28
|
+
@w.start
|
29
|
+
assert_equal(true, File.exists?(@process_file.path))
|
30
|
+
@w.finished
|
31
|
+
assert_equal(false, File.exists?(@process_file.path))
|
32
|
+
|
33
|
+
@w = RerunTask::WatchProcess.new("my_test")
|
34
|
+
@w.start
|
35
|
+
@w2 = RerunTask::WatchProcess.new("my_test")
|
36
|
+
assert_raise_kind_of(RuntimeError) do
|
37
|
+
@w2.start
|
38
|
+
end
|
39
|
+
@w.finished
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_list_pids
|
43
|
+
path = "#{RerunTask::CONFIG['pid_dir']}/rerun_task/pids"
|
44
|
+
filename = "#{path}/test_example_task.rb.pid"
|
45
|
+
FileUtils.rm(filename) if File.exists?(filename)
|
46
|
+
File.open(filename, 'w') do |f|
|
47
|
+
f.write("1234\ntest_example_task.rb")
|
48
|
+
end
|
49
|
+
|
50
|
+
unfinished = RerunTask::Pids.unfinished
|
51
|
+
assert_equal(1, unfinished.size)
|
52
|
+
assert_equal('test_example_task.rb', unfinished.first.process_name)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_run_from_crontab
|
56
|
+
path = "#{RerunTask::CONFIG['pid_dir']}/rerun_task/pids"
|
57
|
+
filename = "#{path}/test_example_task.rb.pid"
|
58
|
+
FileUtils.rm(filename) if File.exists?(filename)
|
59
|
+
File.open(filename, 'w') do |f|
|
60
|
+
f.write("1234\ntest_example_task.rb")
|
61
|
+
end
|
62
|
+
|
63
|
+
crontab = RerunTask::Crontab.new()
|
64
|
+
crontab.content = ["0 0 1,5,9,13,17,21,25,29 * * ruby test_example_task.rb"]
|
65
|
+
res = crontab.find_task('test_example_task.rb')
|
66
|
+
assert_equal("ruby test_example_task.rb", res)
|
67
|
+
|
68
|
+
RerunTask::UnfinishedRunner.crontab_retry()
|
69
|
+
end
|
70
|
+
end
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rerun_task
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- lukasvotypka
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2013-12-23 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: test-unit
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
type: :development
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: mocha
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id002
|
37
|
+
description: This gem is developed for handling rake task and re-run them if didn't finished successfully
|
38
|
+
email:
|
39
|
+
- lukas.votypka@gmail.com
|
40
|
+
executables:
|
41
|
+
- rerun_task_crontab.rb
|
42
|
+
extensions: []
|
43
|
+
|
44
|
+
extra_rdoc_files: []
|
45
|
+
|
46
|
+
files:
|
47
|
+
- .gitignore
|
48
|
+
- Gemfile
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- bin/rerun_task_crontab.rb
|
52
|
+
- config/rerun_task.yml
|
53
|
+
- lib/rerun_task.rb
|
54
|
+
- lib/rerun_task/config.rb
|
55
|
+
- lib/rerun_task/crontab.rb
|
56
|
+
- lib/rerun_task/pids.rb
|
57
|
+
- lib/rerun_task/process_file.rb
|
58
|
+
- lib/rerun_task/unfinished_runner.rb
|
59
|
+
- lib/rerun_task/version.rb
|
60
|
+
- lib/rerun_task/watch_process.rb
|
61
|
+
- rerun_task.gemspec
|
62
|
+
- test/watch_process_test.rb
|
63
|
+
homepage: ""
|
64
|
+
licenses: []
|
65
|
+
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: "0"
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: "0"
|
83
|
+
requirements: []
|
84
|
+
|
85
|
+
rubyforge_project: rerun_task
|
86
|
+
rubygems_version: 1.8.24
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: Re-run task if is not finished
|
90
|
+
test_files:
|
91
|
+
- test/watch_process_test.rb
|
92
|
+
has_rdoc:
|