fork_buddy 0.0.1 → 0.0.2
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/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
|