fork_buddy 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/example-client.rb +5 -0
- data/example.rb +39 -0
- data/lib/fork_buddy.rb +103 -2
- data/lib/fork_buddy/version.rb +1 -1
- data/spec/fork_buddy_spec.rb +0 -0
- data/spec/spec_helper.rb +0 -0
- metadata +11 -6
data/example-client.rb
ADDED
data/example.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'fork_buddy/server'
|
2
|
+
|
3
|
+
fbs = ForkBuddy::Server.start(socket: '/tmp/fork_buddy.sock') do
|
4
|
+
stage :initial {
|
5
|
+
option :rails_env
|
6
|
+
stage :require_bundler {
|
7
|
+
stage :require_application {
|
8
|
+
stage :application_loaded {
|
9
|
+
stage :rspec_ready
|
10
|
+
stage :cucumber_ready
|
11
|
+
}
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
fbs.stage(:initial)
|
18
|
+
|
19
|
+
require 'rubygems'
|
20
|
+
require 'bundler'
|
21
|
+
|
22
|
+
fbs.stage(:require_bundler)
|
23
|
+
|
24
|
+
Bundler.require :default, fbs.option(:rails_env)
|
25
|
+
|
26
|
+
fbs.stage(:require_application)
|
27
|
+
|
28
|
+
ENV['RAILS_ENV'] = fbs.option(:rails_env)
|
29
|
+
require 'application and stuff'
|
30
|
+
|
31
|
+
fbs.stage(:application_booted)
|
32
|
+
|
33
|
+
fbs.stage(:rspec_ready) do
|
34
|
+
require 'rspec/rails'
|
35
|
+
end
|
36
|
+
|
37
|
+
fbs.stage(:cucumber_ready) do
|
38
|
+
require 'cucumber/rails'
|
39
|
+
end
|
data/lib/fork_buddy.rb
CHANGED
@@ -1,5 +1,106 @@
|
|
1
1
|
require "fork_buddy/version"
|
2
|
+
require 'socket'
|
2
3
|
|
3
|
-
|
4
|
-
|
4
|
+
$_stack = []
|
5
|
+
$_children = []
|
6
|
+
|
7
|
+
module Kernel
|
8
|
+
alias_method :__fork, :fork
|
9
|
+
def fork(&block)
|
10
|
+
$_children ||= []
|
11
|
+
r = __fork(&block)
|
12
|
+
$_children << r
|
13
|
+
r
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class ForkBuddy
|
18
|
+
|
19
|
+
class Server
|
20
|
+
def initialize
|
21
|
+
$socket, server = UNIXSocket.pair
|
22
|
+
if __fork
|
23
|
+
@processes = {}
|
24
|
+
begin
|
25
|
+
while line = server.recv(2**12) do
|
26
|
+
process_command(line)
|
27
|
+
end
|
28
|
+
ensure
|
29
|
+
@processes.each { |k, data|
|
30
|
+
Process.kill("QUIT", data[:pid])
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def process_command(line)
|
37
|
+
data = Marshal.load(line)
|
38
|
+
puts "*** #{data.inspect}"
|
39
|
+
|
40
|
+
case data[:command]
|
41
|
+
when :register
|
42
|
+
data.delete(:command)
|
43
|
+
@processes[data[:forkpoint]] = data
|
44
|
+
when :invalidate
|
45
|
+
forkpoint = data[:forkpoint]
|
46
|
+
@processes.each { |k,v|
|
47
|
+
if k == forkpoint || v[:stack].include?(forkpoint)
|
48
|
+
Process.kill("QUIT", v[:pid])
|
49
|
+
v[:prune] = true
|
50
|
+
end
|
51
|
+
}
|
52
|
+
|
53
|
+
restart_forkpoint = @processes.find{|k,v|k==forkpoint}[1][:stack].first
|
54
|
+
restart = @processes.find{|k,v|k==restart_forkpoint}
|
55
|
+
@processes.reject!{|k,v|v[:prune]}
|
56
|
+
|
57
|
+
Process.kill("USR1", restart[1][:pid])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def forkpoint(sym, &block)
|
62
|
+
loop do
|
63
|
+
if pid = __fork
|
64
|
+
data = {
|
65
|
+
command: :register,
|
66
|
+
forkpoint: sym,
|
67
|
+
stack: $_stack,
|
68
|
+
pid: pid
|
69
|
+
}
|
70
|
+
$socket.send Marshal.dump(data), 0
|
71
|
+
|
72
|
+
# Spin until sent the USR1 signal, then run the next iteration of the loop.
|
73
|
+
Kernel.trap("USR1") { throw(:next) }
|
74
|
+
Kernel.trap("USR2") {
|
75
|
+
# Inject code somehow.
|
76
|
+
}
|
77
|
+
catch(:next) { loop { sleep 10 } }
|
78
|
+
else
|
79
|
+
forkpoint_child(block, sym)
|
80
|
+
exit(0) # end of execution reached
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def forkpoint_child(block, sym)
|
86
|
+
Kernel.trap("QUIT") {
|
87
|
+
($_children||[]).each { |child|
|
88
|
+
puts "*** REAPING: #{child}"
|
89
|
+
Process.kill("KILL", child) rescue nil
|
90
|
+
}
|
91
|
+
exit
|
92
|
+
}
|
93
|
+
$_stack.unshift sym
|
94
|
+
block.call
|
95
|
+
end
|
96
|
+
|
97
|
+
def invalidate(sym)
|
98
|
+
data = {
|
99
|
+
command: :invalidate,
|
100
|
+
forkpoint: sym
|
101
|
+
}
|
102
|
+
$socket.send Marshal.dump(data), 0
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
5
106
|
end
|
data/lib/fork_buddy/version.rb
CHANGED
File without changes
|
data/spec/spec_helper.rb
ADDED
File without changes
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fork_buddy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Burke Libbey
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-08-
|
18
|
+
date: 2011-08-20 00:00:00 Z
|
19
19
|
dependencies: []
|
20
20
|
|
21
21
|
description: Write a gem description
|
@@ -31,9 +31,13 @@ files:
|
|
31
31
|
- .gitignore
|
32
32
|
- Gemfile
|
33
33
|
- Rakefile
|
34
|
+
- example-client.rb
|
35
|
+
- example.rb
|
34
36
|
- fork_buddy.gemspec
|
35
37
|
- lib/fork_buddy.rb
|
36
38
|
- lib/fork_buddy/version.rb
|
39
|
+
- spec/fork_buddy_spec.rb
|
40
|
+
- spec/spec_helper.rb
|
37
41
|
homepage: ""
|
38
42
|
licenses: []
|
39
43
|
|
@@ -67,5 +71,6 @@ rubygems_version: 1.7.2
|
|
67
71
|
signing_key:
|
68
72
|
specification_version: 3
|
69
73
|
summary: Write a gem summary
|
70
|
-
test_files:
|
71
|
-
|
74
|
+
test_files:
|
75
|
+
- spec/fork_buddy_spec.rb
|
76
|
+
- spec/spec_helper.rb
|