procrastinate 0.5.0 → 0.6.0

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.
@@ -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'