elf 0.0.1.alpha → 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/README.md CHANGED
@@ -18,7 +18,59 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
- Elves are creatures to manage background processes.
21
+ This code will run 4 parallel processes and will work about 10 seconds
22
+
23
+ ```ruby
24
+ require 'elf'
25
+
26
+ Elf.new do |elf|
27
+ elf.fork("sleep 10")
28
+ elf.fork("sleep 10")
29
+ elf.fork("sleep 10")
30
+ elf.fork("sleep 10")
31
+ end
32
+ ```
33
+
34
+ And this will run each process one by one
35
+
36
+ ```ruby
37
+ require 'elf'
38
+
39
+ Elf.new do |elf|
40
+ elf.sync("sleep 10")
41
+ elf.sync("sleep 10")
42
+ elf.sync("sleep 10")
43
+ elf.sync("sleep 10")
44
+ end
45
+ ```
46
+
47
+ So why do we need this?
48
+
49
+ For example you have got some slow rake tasks, which should be started in particular order. Some of them could be started in parallel, while other shoud work synchronously.
50
+
51
+ You have got this task:
52
+
53
+ 1. Download few big XML files from some server
54
+ 2. Parse them and save to database
55
+ 3. Then you need to combine all this new data and get new big XML file
56
+
57
+ ```ruby
58
+ Elf.new do |elf|
59
+ # let's asynchronously download files and after file is downloaded we will start parse it
60
+ elf.fork("wget file1.xml") do |f|
61
+ f.on_success{ elf.fork("rake some_parser_rake_task") }
62
+ end
63
+ elf.fork("wget file2.xml") do |f|
64
+ f.on_success{ elf.fork("rake some_parser_rake_task") }
65
+ end
66
+ elf.fork("wget file3.xml") do |f|
67
+ f.on_success{ elf.fork("rake some_parser_rake_task") }
68
+ end
69
+
70
+ # Here we are waiting while all data downloaded and parsed and then start new rake task for generating new xml
71
+ elf.sync("rake generate_new_xml")
72
+ end
73
+ ```
22
74
 
23
75
  ## Contributing
24
76
 
@@ -1,31 +1,39 @@
1
1
  module Elf
2
2
  class Child
3
+ attr_reader :success
4
+
3
5
  def initialize(cmd)
4
6
  @cmd = cmd
5
- fire
6
7
  end
7
8
 
8
- def success=(&blk)
9
+ def on_success(&blk)
9
10
  @success = blk
10
- success if @status.exitstatus == 0
11
+ if @status && @status.exitstatus == 0
12
+ success
13
+ end
11
14
  end
12
15
 
13
- def success
16
+ def fire_success
14
17
  puts "Success: #{@cmd}"
15
- @success.call if @success
18
+ if @success
19
+ @success.call
20
+ end
16
21
  end
17
22
 
18
- def error
23
+ def fire_error
19
24
  puts "Failed: #{@cmd}"
20
25
  end
21
26
 
22
27
  def fire
28
+ puts "Fired: #{@cmd}"
23
29
  fork_pid = ::Process.fork do
24
- puts "Fired: #{@cmd}"
25
30
  exec @cmd
26
31
  end
32
+ fake = fork{ "sleep 10" }
27
33
  pid, @status = ::Process.waitpid2(fork_pid)
28
- @status.exitstatus == 0 ? success : error
34
+ @status.exitstatus == 0 ? fire_success : fire_error
35
+ ::Process.kill(9, fake) rescue nil
36
+ ::Process.waitall
29
37
  end
30
38
  end
31
39
  end
@@ -1,10 +1,12 @@
1
1
  module Elf
2
2
  class Fork < Child
3
- alias :sync_fire :fire
4
3
 
4
+ #
5
+ # We can't use Thread's here. because they don't work :)
6
+ #
5
7
  def fire
6
- fork do
7
- sync_fire
8
+ pid = fork do
9
+ super
8
10
  end
9
11
  end
10
12
 
@@ -1,16 +1,20 @@
1
1
  module Elf
2
2
  class Process
3
3
  def initialize(&blk)
4
- blk.call(self)
5
- st = ::Process.waitall
4
+ pid = blk.call(self)
5
+ ::Process.waitall
6
6
  end
7
7
 
8
8
  def fork(cmd)
9
- Elf::Fork.new(cmd)
9
+ elf = Elf::Fork.new(cmd)
10
+ yield elf if block_given?
11
+ pid = elf.fire
10
12
  end
11
13
 
12
14
  def sync(cmd)
13
- Elf::Sync.new(cmd)
15
+ elf = Elf::Sync.new(cmd)
16
+ yield elf if block_given?
17
+ elf.fire
14
18
  end
15
19
  end
16
20
  end
@@ -1,5 +1,10 @@
1
1
  module Elf
2
2
  class Sync < Child
3
3
 
4
+ def fire
5
+ ::Process.waitall
6
+ super
7
+ end
8
+
4
9
  end
5
10
  end
@@ -1,3 +1,3 @@
1
1
  module Elf
2
- VERSION = "0.0.1.alpha"
2
+ VERSION = "0.0.1"
3
3
  end
@@ -16,8 +16,82 @@ describe Elf::Process do
16
16
  start = Time.now
17
17
  Elf::Process.new do |elf|
18
18
  elf.sync("sleep 1")
19
- elf.sync("sleep 2")
20
- elf.sync("sleep 3")
19
+ elf.sync("sleep 1")
20
+ elf.sync("sleep 1")
21
+ end
22
+ (Time.now-start).to_i.must_equal(3)
23
+ end
24
+
25
+ it "should run 4 combined processes" do
26
+ start = Time.now
27
+ Elf::Process.new do |elf|
28
+ elf.fork("sleep 1")
29
+ elf.fork("sleep 1")
30
+ elf.sync("sleep 1")
31
+ elf.sync("sleep 1")
32
+ elf.fork("sleep 1")
33
+ end
34
+ (Time.now-start).to_i.must_equal(4)
35
+ end
36
+
37
+ it "should fire success process" do
38
+ start = Time.now
39
+ Elf::Process.new do |elf|
40
+ elf.fork("sleep 1") do |fork|
41
+ fork.on_success do
42
+ elf.fork("sleep 1")
43
+ end
44
+ end
45
+ elf.sync("sleep 1") do |fork|
46
+ fork.on_success do
47
+ elf.sync("sleep 1")
48
+ end
49
+ end
50
+ elf.sync("sleep 1")
51
+ end
52
+ (Time.now-start).to_i.must_equal(5)
53
+ end
54
+
55
+ it "should work with deep nested success jobs" do
56
+ start = Time.now
57
+ Elf::Process.new do |elf|
58
+ elf.fork("sleep 1") do |f1|
59
+ f1.on_success do
60
+ elf.fork("sleep 1") do |f2|
61
+ f2.on_success do
62
+ elf.fork("sleep 1") do |f3|
63
+ f3.on_success do
64
+ elf.fork("sleep 1")
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ (Time.now-start).to_i.must_equal(4)
73
+ end
74
+
75
+ it "should work with deep nested complex sync async success jobs" do
76
+ start = Time.now
77
+ Elf::Process.new do |elf|
78
+ elf.fork("sleep 1") do |f1|
79
+ f1.on_success do
80
+ elf.fork("sleep 1") do |f2|
81
+ f2.on_success do
82
+ elf.fork("sleep 1") do |f3|
83
+ f3.on_success do
84
+ elf.fork("sleep 1")
85
+ elf.fork("sleep 1")
86
+ elf.fork("sleep 1")
87
+ end
88
+ end
89
+ end
90
+ end
91
+ elf.sync("sleep 1")
92
+ elf.fork("sleep 1")
93
+ end
94
+ end
21
95
  end
22
96
  (Time.now-start).to_i.must_equal(6)
23
97
  end
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.alpha
5
- prerelease: 6
4
+ version: 0.0.1
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Petr Yanovich
@@ -47,9 +47,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
47
47
  required_rubygems_version: !ruby/object:Gem::Requirement
48
48
  none: false
49
49
  requirements:
50
- - - ! '>'
50
+ - - ! '>='
51
51
  - !ruby/object:Gem::Version
52
- version: 1.3.1
52
+ version: '0'
53
53
  requirements: []
54
54
  rubyforge_project:
55
55
  rubygems_version: 1.8.15