procrastinate 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d211f3ecc75813707fd6acdb559783e5b1aa7124
4
+ data.tar.gz: 863ff06f3edb224c5edca1f38d88455a7c1c844f
5
+ SHA512:
6
+ metadata.gz: 7adc67259467bdfc350ea453de21574447deabff894ad65d80586b096a6306390be1729a06e5bdd00c61423ebd6bcb31835ef2efcdb1515b7057fd32acdac8a4
7
+ data.tar.gz: 62e94303c101c092b49efdb3f759169075f03e2972a3ec3ffe4d9c77d2973e0b12fe1137dc5cf98fc19a3ff9f2c0927bf03cc916aeb8cdebedc34fa855b517e7
@@ -1,3 +1,9 @@
1
+ = 0.6 / 20Nov2013
2
+
3
+ - Removes the cod gem and replaces it with a correct parent child
4
+ communication.
5
+ - Makes sure this works with Ruby 2.0
6
+
1
7
  = 0.5 / last minor release: 18Dez2012
2
8
 
3
9
  + Replaces the custom IPC implementation with the cod gem.
data/README CHANGED
@@ -55,7 +55,7 @@ The above example will output something like
55
55
 
56
56
  COMPATIBILITY
57
57
 
58
- This library runs with at least Ruby 1.8.7 and Ruby 1.9.
58
+ This library runs with MRI Ruby >= 1.9.
59
59
 
60
60
  Ruby 1.9-p136 users must use this patch:
61
61
  https://gist.github.com/762807
@@ -1,6 +1,5 @@
1
1
 
2
2
  require 'state_machine'
3
- require 'cod'
4
3
 
5
4
  # Dispatches and handles tasks and task completion. Only low level unixy
6
5
  # manipulation here, no strategy. The only methods you should call from the
@@ -23,9 +22,6 @@ class Procrastinate::ProcessManager
23
22
 
24
23
  # All presently running children
25
24
  @children = {}
26
-
27
- # Master should read from @master, Children write to @child
28
- @master, @child = Cod.pipe.split
29
25
  end
30
26
 
31
27
  # Sets up resource usage for dispatcher. You must call this before dispatcher
@@ -95,21 +91,31 @@ class Procrastinate::ProcessManager
95
91
  cp_read_end = control_pipe.first
96
92
 
97
93
  loop do # until we have input in the cp_read_end (control_pipe)
98
- # TODO Why does procrastinate (cod) hang sometimes when there is no
99
- # timeout here? What messages are we missing?
100
- ready = Cod.select(1,
101
- :child_msgs => @master, :control_pipe => cp_read_end)
102
-
103
- read_child_messages if ready.has_key?(:child_msgs)
94
+ io_map = children.inject({}) { |map, (_, child)|
95
+ map[child.master_pipe] = child; map }
96
+
97
+ ready, _, _ = IO.select(io_map.keys + [cp_read_end], [], [], 0.1)
98
+ next unless ready
99
+
100
+ # Process all messages that were sent from our childs to us.
101
+ ready.each { |io|
102
+ next if io == cp_read_end
104
103
 
104
+ child = io_map[io]
105
+
106
+ fail "Assert: All IOs correspond to a child" unless child
107
+ child.read_message
108
+ }
109
+
105
110
  # Send the tracking code for the child processes the final notifications
106
111
  # and remove them from the children hash. At this point we know that
107
112
  # no messages are waiting in the child queue.
108
113
  finalize_children
109
114
 
110
- if ready.has_key?(:control_pipe)
115
+ if ready.include?(cp_read_end)
111
116
  # Consume the data (not important)
112
117
  cp_read_end.read_nonblock(1024)
118
+ # And return to our caller. This is the event we've been waiting for.
113
119
  return
114
120
  end
115
121
  end
@@ -124,28 +130,6 @@ class Procrastinate::ProcessManager
124
130
  child.removable? }
125
131
  end
126
132
 
127
- def read_child_messages
128
- loop do
129
- ready = Cod.select(0.1, @master)
130
- break unless ready
131
-
132
- handle_message @master.get
133
- end
134
- end
135
-
136
- # Called for every message sent from a child. The +msg+ param here is a string
137
- # that still needs decoding.
138
- #
139
- def handle_message(msg)
140
- pid, obj = msg
141
-
142
- if child=children[pid]
143
- child.incoming_message(obj)
144
- else
145
- warn "Communication from child #{pid} received, but child is gone."
146
- end
147
- end
148
-
149
133
  # Calls completion handlers for all the childs that have now exited.
150
134
  #
151
135
  def reap_childs
@@ -183,12 +167,13 @@ class Procrastinate::ProcessManager
183
167
  # Tasks that are interested in getting messages from their childs must
184
168
  # provide a result object that handles incoming 'result' messages.
185
169
  result = task.result
170
+ child_process = ChildProcess.new(completion_handler, result)
186
171
 
187
172
  pid = fork do
188
173
  cleanup
189
174
 
190
175
  if result
191
- endpoint = lambda { |obj| @child.put [Process.pid, obj] }
176
+ endpoint = lambda { |obj| child_process.send_message(obj) }
192
177
  task.run(endpoint)
193
178
  else
194
179
  task.run(nil)
@@ -204,8 +189,7 @@ class Procrastinate::ProcessManager
204
189
  # The spawning is done in the same thread as the reaping is done. This is
205
190
  # why no race condition to the following line exists. (or in other code,
206
191
  # for that matter.)
207
- children[pid] = ChildProcess.new(completion_handler, result).
208
- tap { |s| s.start }
192
+ children[pid] = child_process.tap { |s| s.start }
209
193
  end
210
194
 
211
195
  # Gets executed in child process to clean up file handles and pipes that the
@@ -4,9 +4,13 @@
4
4
  #
5
5
  Procrastinate::ProcessManager::ChildProcess =
6
6
  Struct.new(:handler, :result, :state) do
7
+
8
+ attr_reader :master_pipe, :child_pipe
7
9
 
8
10
  def initialize(handler, result)
9
11
  super(handler, result, "new")
12
+
13
+ @master_pipe, @child_pipe = IO.pipe
10
14
  end
11
15
 
12
16
  state_machine :state, :initial => :new do
@@ -33,6 +37,10 @@ Procrastinate::ProcessManager::ChildProcess =
33
37
  #
34
38
  def notify_result
35
39
  result.process_died if result
40
+
41
+ # The child is now officially dead, so we don't need these anymore:
42
+ @master_pipe.close
43
+ @child_pipe.close
36
44
  end
37
45
 
38
46
  # Handles incoming messages from the tasks process.
@@ -40,4 +48,17 @@ Procrastinate::ProcessManager::ChildProcess =
40
48
  def incoming_message(obj)
41
49
  result.incoming_message(obj) if result
42
50
  end
51
+
52
+ # Read and process a message from the process that is connected to this
53
+ # object. Normally, we would make sure that such a message is indeed waiting
54
+ # on the master_pipe by means of an IO select.
55
+ #
56
+ def read_message
57
+ msg = Marshal.load(master_pipe)
58
+ incoming_message(msg)
59
+ end
60
+
61
+ def send_message obj
62
+ Marshal.dump(obj, child_pipe)
63
+ end
43
64
  end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: procrastinate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
5
- prerelease:
4
+ version: 0.6.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Kaspar Schiess
@@ -10,136 +9,106 @@ authors:
10
9
  autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2012-12-18 00:00:00.000000000 Z
12
+ date: 2013-11-20 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: state_machine
17
- prerelease: false
18
16
  requirement: !ruby/object:Gem::Requirement
19
17
  requirements:
20
18
  - - ~>
21
19
  - !ruby/object:Gem::Version
22
20
  version: '1.1'
23
- none: false
24
21
  type: :runtime
25
- version_requirements: !ruby/object:Gem::Requirement
26
- requirements:
27
- - - ~>
28
- - !ruby/object:Gem::Version
29
- version: '1.1'
30
- none: false
31
- - !ruby/object:Gem::Dependency
32
- name: cod
33
22
  prerelease: false
34
- requirement: !ruby/object:Gem::Requirement
35
- requirements:
36
- - - ~>
37
- - !ruby/object:Gem::Version
38
- version: '0.5'
39
- none: false
40
- type: :runtime
41
23
  version_requirements: !ruby/object:Gem::Requirement
42
24
  requirements:
43
25
  - - ~>
44
26
  - !ruby/object:Gem::Version
45
- version: '0.5'
46
- none: false
27
+ version: '1.1'
47
28
  - !ruby/object:Gem::Dependency
48
29
  name: rake
49
- prerelease: false
50
30
  requirement: !ruby/object:Gem::Requirement
51
31
  requirements:
52
- - - ! '>='
32
+ - - '>='
53
33
  - !ruby/object:Gem::Version
54
34
  version: '0'
55
- none: false
56
35
  type: :development
36
+ prerelease: false
57
37
  version_requirements: !ruby/object:Gem::Requirement
58
38
  requirements:
59
- - - ! '>='
39
+ - - '>='
60
40
  - !ruby/object:Gem::Version
61
41
  version: '0'
62
- none: false
63
42
  - !ruby/object:Gem::Dependency
64
43
  name: rspec
65
- prerelease: false
66
44
  requirement: !ruby/object:Gem::Requirement
67
45
  requirements:
68
- - - ! '>='
46
+ - - '>='
69
47
  - !ruby/object:Gem::Version
70
48
  version: '0'
71
- none: false
72
49
  type: :development
50
+ prerelease: false
73
51
  version_requirements: !ruby/object:Gem::Requirement
74
52
  requirements:
75
- - - ! '>='
53
+ - - '>='
76
54
  - !ruby/object:Gem::Version
77
55
  version: '0'
78
- none: false
79
56
  - !ruby/object:Gem::Dependency
80
57
  name: flexmock
81
- prerelease: false
82
58
  requirement: !ruby/object:Gem::Requirement
83
59
  requirements:
84
- - - ! '>='
60
+ - - '>='
85
61
  - !ruby/object:Gem::Version
86
62
  version: '0'
87
- none: false
88
63
  type: :development
64
+ prerelease: false
89
65
  version_requirements: !ruby/object:Gem::Requirement
90
66
  requirements:
91
- - - ! '>='
67
+ - - '>='
92
68
  - !ruby/object:Gem::Version
93
69
  version: '0'
94
- none: false
95
70
  - !ruby/object:Gem::Dependency
96
71
  name: guard
97
- prerelease: false
98
72
  requirement: !ruby/object:Gem::Requirement
99
73
  requirements:
100
- - - ! '>='
74
+ - - '>='
101
75
  - !ruby/object:Gem::Version
102
76
  version: '0'
103
- none: false
104
77
  type: :development
78
+ prerelease: false
105
79
  version_requirements: !ruby/object:Gem::Requirement
106
80
  requirements:
107
- - - ! '>='
81
+ - - '>='
108
82
  - !ruby/object:Gem::Version
109
83
  version: '0'
110
- none: false
111
84
  - !ruby/object:Gem::Dependency
112
85
  name: growl
113
- prerelease: false
114
86
  requirement: !ruby/object:Gem::Requirement
115
87
  requirements:
116
- - - ! '>='
88
+ - - '>='
117
89
  - !ruby/object:Gem::Version
118
90
  version: '0'
119
- none: false
120
91
  type: :development
92
+ prerelease: false
121
93
  version_requirements: !ruby/object:Gem::Requirement
122
94
  requirements:
123
- - - ! '>='
95
+ - - '>='
124
96
  - !ruby/object:Gem::Version
125
97
  version: '0'
126
- none: false
127
98
  - !ruby/object:Gem::Dependency
128
99
  name: yard
129
- prerelease: false
130
100
  requirement: !ruby/object:Gem::Requirement
131
101
  requirements:
132
- - - ! '>='
102
+ - - '>='
133
103
  - !ruby/object:Gem::Version
134
104
  version: '0'
135
- none: false
136
105
  type: :development
106
+ prerelease: false
137
107
  version_requirements: !ruby/object:Gem::Requirement
138
108
  requirements:
139
- - - ! '>='
109
+ - - '>='
140
110
  - !ruby/object:Gem::Version
141
111
  version: '0'
142
- none: false
143
112
  description:
144
113
  email:
145
114
  - kaspar.schiess@absurd.li
@@ -151,7 +120,6 @@ extra_rdoc_files:
151
120
  files:
152
121
  - HISTORY.txt
153
122
  - LICENSE
154
- - Rakefile
155
123
  - README
156
124
  - lib/procrastinate/implicit.rb
157
125
  - lib/procrastinate/lock.rb
@@ -178,7 +146,9 @@ files:
178
146
  - examples/simple.rb
179
147
  - examples/throttled.rb
180
148
  homepage: http://github.com/kschiess/procrastinate
181
- licenses: []
149
+ licenses:
150
+ - MIT
151
+ metadata: {}
182
152
  post_install_message:
183
153
  rdoc_options:
184
154
  - --main
@@ -187,21 +157,19 @@ require_paths:
187
157
  - lib
188
158
  required_ruby_version: !ruby/object:Gem::Requirement
189
159
  requirements:
190
- - - ! '>='
160
+ - - '>='
191
161
  - !ruby/object:Gem::Version
192
162
  version: '0'
193
- none: false
194
163
  required_rubygems_version: !ruby/object:Gem::Requirement
195
164
  requirements:
196
- - - ! '>='
165
+ - - '>='
197
166
  - !ruby/object:Gem::Version
198
167
  version: '0'
199
- none: false
200
168
  requirements: []
201
169
  rubyforge_project:
202
- rubygems_version: 1.8.24
170
+ rubygems_version: 2.0.6
203
171
  signing_key:
204
- specification_version: 3
172
+ specification_version: 4
205
173
  summary: Framework to run tasks in separate processes.
206
174
  test_files: []
207
175
  has_rdoc:
data/Rakefile DELETED
@@ -1,36 +0,0 @@
1
- require "rubygems"
2
- require 'rspec/core/rake_task'
3
- require 'rubygems/package_task'
4
- require 'rake/clean'
5
-
6
- desc "Run all tests: Exhaustive."
7
- RSpec::Core::RakeTask.new
8
-
9
- task :default => :spec
10
-
11
- task :stats do
12
- %w(lib spec).each do |path|
13
- printf "%10s:", path
14
- system %Q(find #{path} -name "*.rb" | xargs wc -l | grep total)
15
- end
16
- end
17
-
18
- require 'yard'
19
- YARD::Rake::YardocTask.new do |t|
20
- # t.files = ['lib/**/*.rb']
21
- # t.options = ['--any', '--extra', '--opts'] # optional
22
- end
23
-
24
- desc 'Clear out RDoc'
25
- task :clean => [:clobber_package]
26
-
27
- # This task actually builds the gem.
28
- task :gem => :spec
29
- spec = eval(File.read('procrastinate.gemspec'))
30
-
31
- desc "Generate the gem package."
32
- Gem::PackageTask.new(spec) do |pkg|
33
- # pkg.need_tar = true
34
- end
35
-
36
- CLEAN << 'doc'