rerun_task 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.
- 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:
|