procrastinate 0.4.0 → 0.4.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/HISTORY.txt CHANGED
@@ -1,4 +1,8 @@
1
- = 0.4.0 / ???
1
+ = 0.4.1 / 23Jan2012
2
+
3
+ + Replaces the custom IPC implementation with the cod gem.
4
+
5
+ = 0.4.0 / 16Dez2011
2
6
 
3
7
  + Schedules blocks as well (Scheduler#schedule).
4
8
 
data/lib/procrastinate.rb CHANGED
@@ -7,7 +7,6 @@ module Procrastinate
7
7
 
8
8
  autoload :Lock, 'procrastinate/lock'
9
9
  autoload :Runtime, 'procrastinate/runtime'
10
- autoload :IPC, 'procrastinate/ipc'
11
10
  autoload :Task, 'procrastinate/task'
12
11
  end
13
12
 
@@ -1,14 +1,12 @@
1
1
 
2
2
  require 'state_machine'
3
+ require 'cod'
3
4
 
4
5
  # Dispatches and handles tasks and task completion. Only low level unixy
5
6
  # manipulation here, no strategy. The only methods you should call from the
6
7
  # outside are #setup, #step, #wakeup and #shutdown.
7
8
  #
8
9
  class Procrastinate::ProcessManager
9
- include Procrastinate::IPC
10
-
11
- autoload :ObjectEndpoint, 'procrastinate/process_manager/object_endpoint'
12
10
  autoload :ChildProcess, 'procrastinate/process_manager/child_process'
13
11
 
14
12
  # This pipe is used to wait for events in the master process.
@@ -25,11 +23,9 @@ class Procrastinate::ProcessManager
25
23
 
26
24
  # All presently running children
27
25
  @children = {}
28
-
29
- # Child Master Communication (cmc)
30
- endpoint = Endpoint.anonymous
31
- @cmc_server = endpoint.server
32
- @cmc_client = endpoint.client
26
+
27
+ # Master should read from @master, Children write to @child
28
+ @master, @child = Cod.pipe.split
33
29
  end
34
30
 
35
31
  # Sets up resource usage for dispatcher. You must call this before dispatcher
@@ -99,16 +95,19 @@ class Procrastinate::ProcessManager
99
95
  cp_read_end = control_pipe.first
100
96
 
101
97
  loop do # until we have input in the cp_read_end (control_pipe)
102
- ready = Endpoint.select([cp_read_end, @cmc_server])
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)
103
102
 
104
- read_child_messages if ready.include? @cmc_server
103
+ read_child_messages if ready.has_key?(:child_msgs)
105
104
 
106
105
  # Send the tracking code for the child processes the final notifications
107
106
  # and remove them from the children hash. At this point we know that
108
107
  # no messages are waiting in the child queue.
109
108
  finalize_children
110
109
 
111
- if ready.include? cp_read_end
110
+ if ready.has_key?(:control_pipe)
112
111
  # Consume the data (not important)
113
112
  cp_read_end.read_nonblock(1024)
114
113
  return
@@ -125,28 +124,20 @@ class Procrastinate::ProcessManager
125
124
  child.removable? }
126
125
  end
127
126
 
128
- # Once the @cmc_server endpoint is ready, loops and reads all child
129
- # communication.
130
- #
131
127
  def read_child_messages
132
128
  loop do
133
- msg = @cmc_server.receive
134
- decode_and_handle_message(msg)
129
+ ready = Cod.select(0.1, @master)
130
+ break unless ready
135
131
 
136
- break unless @cmc_server.waiting?
132
+ handle_message @master.get
137
133
  end
138
134
  end
139
135
 
140
136
  # Called for every message sent from a child. The +msg+ param here is a string
141
137
  # that still needs decoding.
142
138
  #
143
- def decode_and_handle_message(msg)
144
- pid, obj = begin
145
- Marshal.load(msg)
146
- rescue => b
147
- # Messages that cannot be unmarshalled will be ignored.
148
- warn "Can't unmarshal child communication: #{b}"
149
- end
139
+ def handle_message(msg)
140
+ pid, obj = msg
150
141
 
151
142
  if child=children[pid]
152
143
  child.incoming_message(obj)
@@ -192,7 +183,7 @@ class Procrastinate::ProcessManager
192
183
  cleanup
193
184
 
194
185
  if result
195
- endpoint = ObjectEndpoint.new(@cmc_client, Process.pid)
186
+ endpoint = lambda { |obj| @child.put [Process.pid, obj] }
196
187
  task.run(endpoint)
197
188
  else
198
189
  task.run(nil)
@@ -227,9 +218,10 @@ class Procrastinate::ProcessManager
227
218
  #
228
219
  def wait_for_all_childs
229
220
  # TODO Maybe signal KILL to children after some time.
230
- until children.all? { |p, c| c.dead? }
221
+ until children.empty?
231
222
  wait_for_event
232
223
  reap_childs
224
+ finalize_children
233
225
  end
234
226
  end
235
227
  end
@@ -21,7 +21,7 @@ module Procrastinate::Task
21
21
  #
22
22
  def run(endpoint)
23
23
  r = @b.call
24
- endpoint.send r if endpoint
24
+ endpoint.call(r) if endpoint
25
25
  end
26
26
  end
27
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: procrastinate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2011-12-16 00:00:00.000000000 Z
13
+ date: 2012-01-23 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: state_machine
17
- requirement: &70314600072220 !ruby/object:Gem::Requirement
17
+ requirement: &70180063938160 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ~>
@@ -22,10 +22,32 @@ dependencies:
22
22
  version: 0.9.4
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *70314600072220
25
+ version_requirements: *70180063938160
26
+ - !ruby/object:Gem::Dependency
27
+ name: cod
28
+ requirement: &70180063966580 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '0.4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *70180063966580
37
+ - !ruby/object:Gem::Dependency
38
+ name: rake
39
+ requirement: &70180063963140 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *70180063963140
26
48
  - !ruby/object:Gem::Dependency
27
49
  name: rspec
28
- requirement: &70314600070260 !ruby/object:Gem::Requirement
50
+ requirement: &70180063959700 !ruby/object:Gem::Requirement
29
51
  none: false
30
52
  requirements:
31
53
  - - ! '>='
@@ -33,10 +55,10 @@ dependencies:
33
55
  version: '0'
34
56
  type: :development
35
57
  prerelease: false
36
- version_requirements: *70314600070260
58
+ version_requirements: *70180063959700
37
59
  - !ruby/object:Gem::Dependency
38
60
  name: flexmock
39
- requirement: &70314600069360 !ruby/object:Gem::Requirement
61
+ requirement: &70180063973380 !ruby/object:Gem::Requirement
40
62
  none: false
41
63
  requirements:
42
64
  - - ! '>='
@@ -44,7 +66,29 @@ dependencies:
44
66
  version: '0'
45
67
  type: :development
46
68
  prerelease: false
47
- version_requirements: *70314600069360
69
+ version_requirements: *70180063973380
70
+ - !ruby/object:Gem::Dependency
71
+ name: guard
72
+ requirement: &70180063972060 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: *70180063972060
81
+ - !ruby/object:Gem::Dependency
82
+ name: growl
83
+ requirement: &70180063970680 !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: *70180063970680
48
92
  description:
49
93
  email:
50
94
  - kaspar.schiess@absurd.li
@@ -59,11 +103,8 @@ files:
59
103
  - Rakefile
60
104
  - README
61
105
  - lib/procrastinate/implicit.rb
62
- - lib/procrastinate/ipc/endpoint.rb
63
- - lib/procrastinate/ipc.rb
64
106
  - lib/procrastinate/lock.rb
65
107
  - lib/procrastinate/process_manager/child_process.rb
66
- - lib/procrastinate/process_manager/object_endpoint.rb
67
108
  - lib/procrastinate/process_manager.rb
68
109
  - lib/procrastinate/proxy.rb
69
110
  - lib/procrastinate/runtime.rb
@@ -99,13 +140,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
99
140
  version: '0'
100
141
  segments:
101
142
  - 0
102
- hash: 4532369798177350543
143
+ hash: 3407763989240963082
103
144
  required_rubygems_version: !ruby/object:Gem::Requirement
104
145
  none: false
105
146
  requirements:
106
147
  - - ! '>='
107
148
  - !ruby/object:Gem::Version
108
149
  version: '0'
150
+ segments:
151
+ - 0
152
+ hash: 3407763989240963082
109
153
  requirements: []
110
154
  rubyforge_project:
111
155
  rubygems_version: 1.8.10
@@ -1,6 +0,0 @@
1
-
2
- # Holds classes for interprocess communication.
3
- #
4
- module Procrastinate::IPC
5
- autoload :Endpoint, 'procrastinate/ipc/endpoint'
6
- end
@@ -1,106 +0,0 @@
1
-
2
- # A communication endpoint. This acts as a factory and hub for the whole
3
- # IPC library.
4
- #
5
- module Procrastinate::IPC::Endpoint
6
- def anonymous
7
- Anonymous.new
8
- end
9
- module_function :anonymous
10
-
11
- # Works the same as IO.select, only that it doesn't care about write and
12
- # error readiness, only read. You can mix IPC::Endpoints and normal IO
13
- # instances freely.
14
- #
15
- def select(read_array, timeout=nil)
16
- # This maps real system IO instances to wrapper objects. Return the thing
17
- # to the right if IO.select returns the thing to the left.
18
- mapping = Hash.new
19
- waiting = []
20
-
21
- read_array.each { |io_or_endpoint|
22
- if io_or_endpoint.respond_to?(:select_ios)
23
- waiting << io_or_endpoint if io_or_endpoint.waiting?
24
-
25
- io_or_endpoint.select_ios.each do |io|
26
- mapping[io] = io_or_endpoint
27
- end
28
- else
29
- mapping[io_or_endpoint] = io_or_endpoint
30
- end
31
- }
32
-
33
- return waiting unless waiting.empty?
34
-
35
- system_io = IO.select(mapping.keys, nil, nil, timeout)
36
- if system_io
37
- return system_io.first.
38
- # Map returned selectors to their object counterparts and then only
39
- # return once (if more than one was returned).
40
- map { |e| mapping[e] }.uniq
41
- end
42
- end
43
- module_function :select
44
-
45
- class Anonymous
46
- def initialize
47
- @re, @we = IO.pipe
48
- end
49
-
50
- def server
51
- Server.new(@re)
52
- end
53
- def client
54
- Client.new(@we)
55
- end
56
- end
57
-
58
- class Anonymous::Server
59
- attr_reader :pipe
60
- attr_reader :waiting
61
- def initialize(pipe)
62
- @pipe = pipe
63
- @waiting = Array.new
64
- end
65
-
66
- def receive(timeout=nil)
67
- return waiting.shift if waiting?
68
-
69
- loop do
70
- buffer = pipe.read_nonblock(1024*1024*1024)
71
-
72
- while buffer.size > 0
73
- size = buffer.slice!(0...4).unpack('l').first
74
- waiting << buffer.slice!(0...size)
75
- end
76
-
77
- return waiting.shift if waiting?
78
- end
79
- end
80
-
81
- # True if there are queued messages in the Endpoint stack. If this is
82
- # false, a receive might block.
83
- #
84
- def waiting?
85
- not waiting.empty?
86
- end
87
-
88
- # Return underlying IOs for select.
89
- #
90
- def select_ios
91
- [@pipe]
92
- end
93
- end
94
-
95
- class Anonymous::Client
96
- attr_reader :pipe
97
- def initialize(pipe)
98
- @pipe = pipe
99
- end
100
-
101
- def send(msg)
102
- buffer = [msg.size].pack('l') + msg
103
- pipe.write(buffer)
104
- end
105
- end
106
- end
@@ -1,10 +0,0 @@
1
- # A class that acts as a filter between ProcessManager and the endpoint it
2
- # uses to communicate with its children. This converts Ruby objects into
3
- # Strings and also sends process id.
4
- #
5
- class Procrastinate::ProcessManager::ObjectEndpoint < Struct.new(:endpoint, :pid)
6
- def send(obj)
7
- msg = Marshal.dump([pid, obj])
8
- endpoint.send(msg)
9
- end
10
- end