procrastinate 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
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