expedite 0.2.2 → 0.2.4
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.
- checksums.yaml +4 -4
- data/README.md +16 -8
- data/lib/expedite/action/block.rb +2 -1
- data/lib/expedite/action/boot.rb +7 -6
- data/lib/expedite/agents.rb +18 -16
- data/lib/expedite/client/agent_proxy.rb +27 -0
- data/lib/expedite/client/base.rb +10 -8
- data/lib/expedite/env.rb +26 -8
- data/lib/expedite/errors.rb +6 -0
- data/lib/expedite/hooks.rb +46 -0
- data/lib/expedite/protocol.rb +50 -1
- data/lib/expedite/server/agent.rb +36 -30
- data/lib/expedite/server/agent_boot.rb +1 -1
- data/lib/expedite/server/agent_manager.rb +25 -23
- data/lib/expedite/server/controller.rb +9 -10
- data/lib/expedite/syntax.rb +4 -2
- data/lib/expedite/version.rb +1 -1
- data/lib/expedite.rb +6 -25
- metadata +5 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ece07855912fe5042042713eb78fecedc03cd06f5b495c0f17a1e7dab14ee99e
|
|
4
|
+
data.tar.gz: c94ea277e1a83968b187648d5917ed2e42181c81f3a3a04c4c6acafc1c52fbf5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: eb9688825664432ab5e7f5ef60ee855715eabcf6e25ee9242c6eca816c99bb7431eb36ad12b1124e11401dd961b4d68868077c41c9dd8f6b5bb20ffc854a1e09
|
|
7
|
+
data.tar.gz: baf6f7c68c3f98eccf8651947b72dd7e3150580d886015038e7ccd68e0c63798db82e8b6977c1f974a1c027112a233dc0fc227b002cb763151c3916fbda58a5f
|
data/README.md
CHANGED
|
@@ -16,7 +16,9 @@ This is the "parent" agent:
|
|
|
16
16
|
```
|
|
17
17
|
Expedite.define do
|
|
18
18
|
agent :parent do
|
|
19
|
-
|
|
19
|
+
before(:serve) do |name|
|
|
20
|
+
$parent_var = name
|
|
21
|
+
end
|
|
20
22
|
end
|
|
21
23
|
end
|
|
22
24
|
```
|
|
@@ -26,8 +28,12 @@ matchers.
|
|
|
26
28
|
|
|
27
29
|
```
|
|
28
30
|
Expedite.define do
|
|
29
|
-
agent "development/*"
|
|
30
|
-
|
|
31
|
+
agent "development/*" do
|
|
32
|
+
self.parent = :parent
|
|
33
|
+
|
|
34
|
+
before(:serve) do |name|
|
|
35
|
+
$child_var = name
|
|
36
|
+
end
|
|
31
37
|
end
|
|
32
38
|
end
|
|
33
39
|
```
|
|
@@ -37,10 +43,12 @@ The following defines an `info` action.
|
|
|
37
43
|
```
|
|
38
44
|
Expedite.define do
|
|
39
45
|
action :info do
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
{
|
|
47
|
+
"Process.pid" => Process.pid,
|
|
48
|
+
"Process.ppid" => Process.ppid,
|
|
49
|
+
"$parent_var" => $parent_var,
|
|
50
|
+
"$child_var" => $child_var,
|
|
51
|
+
}
|
|
44
52
|
end
|
|
45
53
|
end
|
|
46
54
|
```
|
|
@@ -55,7 +63,7 @@ the action; in that case, the return result is the exit code.
|
|
|
55
63
|
```
|
|
56
64
|
require 'expedite'
|
|
57
65
|
|
|
58
|
-
Expedite.agent("development/abc").invoke("info")
|
|
66
|
+
puts Expedite.agent("development/abc").invoke("info")
|
|
59
67
|
```
|
|
60
68
|
|
|
61
69
|
When you run `main.rb`, the following output is produced. Note that `$sleep_parent`
|
|
@@ -3,7 +3,7 @@ module Expedite
|
|
|
3
3
|
module Action
|
|
4
4
|
class Block
|
|
5
5
|
attr_reader :runs_in
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
def initialize(runs_in: :application, &block)
|
|
8
8
|
@runs_in = runs_in
|
|
9
9
|
@block = block
|
|
@@ -13,6 +13,7 @@ module Expedite
|
|
|
13
13
|
@block.call(*args)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
# Ignoring all streams
|
|
16
17
|
def setup(_)
|
|
17
18
|
end
|
|
18
19
|
end
|
data/lib/expedite/action/boot.rb
CHANGED
|
@@ -2,12 +2,12 @@ module Expedite
|
|
|
2
2
|
module Action
|
|
3
3
|
class Boot
|
|
4
4
|
def call(*args)
|
|
5
|
-
|
|
5
|
+
name = args[0]
|
|
6
6
|
|
|
7
7
|
require "expedite/server/agent"
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
Expedite::Server::Agent.new(
|
|
10
|
-
|
|
10
|
+
name: name,
|
|
11
11
|
manager: UNIXSocket.for_fd(@child_socket.fileno),
|
|
12
12
|
env: Expedite::Env.new(
|
|
13
13
|
root: ENV['EXPEDITE_ROOT'],
|
|
@@ -16,9 +16,10 @@ module Expedite
|
|
|
16
16
|
).boot
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@log_file =
|
|
19
|
+
# STDOUT, STDERR, STDIN, log, child_socket
|
|
20
|
+
def setup(streams)
|
|
21
|
+
@log_file = streams[3]
|
|
22
|
+
@child_socket = streams[4]
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
def runs_in
|
data/lib/expedite/agents.rb
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
require 'expedite/hooks'
|
|
1
2
|
|
|
2
3
|
module Expedite
|
|
3
4
|
# Definition of a Agent
|
|
4
5
|
class Agent
|
|
6
|
+
include Hooks
|
|
7
|
+
|
|
5
8
|
##
|
|
6
9
|
# Name of the parent agent. This allows you to create agents from
|
|
7
10
|
# an existing agent.
|
|
@@ -16,18 +19,20 @@ module Expedite
|
|
|
16
19
|
##
|
|
17
20
|
# [parent] Name of parent agent.
|
|
18
21
|
# [keep_alive] Specifies if the agent should be automatically restarted if it is terminated. Defaults to false.
|
|
19
|
-
|
|
20
|
-
def initialize(parent: nil, keep_alive: false, &after_fork)
|
|
22
|
+
def initialize(parent: nil, keep_alive: false)
|
|
21
23
|
@parent = parent
|
|
22
24
|
@keep_alive = keep_alive
|
|
23
|
-
@after_fork_proc = after_fork
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
##
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
def
|
|
30
|
-
|
|
28
|
+
# Register a before event
|
|
29
|
+
# @params event [String] Allowed values: :run
|
|
30
|
+
def before(event, &block)
|
|
31
|
+
register_hook(:"before_#{event}", block)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def after(event, &block)
|
|
35
|
+
register_hook(:"after_#{event}", block)
|
|
31
36
|
end
|
|
32
37
|
end
|
|
33
38
|
|
|
@@ -54,8 +59,6 @@ module Expedite
|
|
|
54
59
|
#
|
|
55
60
|
# [matcher] Wildcard to match a name against.
|
|
56
61
|
# [named_options] Agent options.
|
|
57
|
-
# [after_fork] Optional block that is called when
|
|
58
|
-
# agent is preloaded.
|
|
59
62
|
#
|
|
60
63
|
# = Example
|
|
61
64
|
# Expedite::Agents.register('base' do |name|
|
|
@@ -64,8 +67,8 @@ module Expedite
|
|
|
64
67
|
# Expedite::Agents.register('development/abc', parent: 'base') do |name|
|
|
65
68
|
# puts "Agent #{name} started"
|
|
66
69
|
# end
|
|
67
|
-
def self.register(matcher, **named_options
|
|
68
|
-
self.current.register(matcher.to_s, **named_options
|
|
70
|
+
def self.register(matcher, **named_options)
|
|
71
|
+
self.current.register(matcher.to_s, **named_options)
|
|
69
72
|
end
|
|
70
73
|
|
|
71
74
|
##
|
|
@@ -86,11 +89,10 @@ module Expedite
|
|
|
86
89
|
ret.agent
|
|
87
90
|
end
|
|
88
91
|
|
|
89
|
-
def register(matcher, **named_options
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
)
|
|
92
|
+
def register(matcher, **named_options)
|
|
93
|
+
agent = Agent.new(**named_options)
|
|
94
|
+
@registrations << Registration.new(matcher, agent)
|
|
95
|
+
agent
|
|
94
96
|
end
|
|
95
97
|
|
|
96
98
|
def reset
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'expedite/client/exec'
|
|
2
|
+
require 'expedite/client/invoke'
|
|
3
|
+
|
|
4
|
+
module Expedite
|
|
5
|
+
module Client
|
|
6
|
+
class AgentProxy
|
|
7
|
+
attr_accessor :name, :env
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
#
|
|
11
|
+
# @param name [String] Name of the agent
|
|
12
|
+
# @param env [Expedite::Env] Environment
|
|
13
|
+
def initialize(name, env:)
|
|
14
|
+
self.name = name
|
|
15
|
+
self.env = env
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def exec(*args)
|
|
19
|
+
Client::Exec.new(env: env, agent: name).call(*args)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def invoke(*args)
|
|
23
|
+
Client::Invoke.new(env: env, agent: name).call(*args)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/expedite/client/base.rb
CHANGED
|
@@ -59,11 +59,11 @@ module Expedite
|
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
def run_command(client, agent, args)
|
|
62
|
+
@null_socket ||= File.open(File::NULL, "a")
|
|
62
63
|
log "sending command"
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
agent.
|
|
66
|
-
agent.send_io STDIN
|
|
65
|
+
# No child socket
|
|
66
|
+
agent.send_setup(@null_socket, env)
|
|
67
67
|
|
|
68
68
|
agent.send_object({
|
|
69
69
|
"args" => args,
|
|
@@ -85,7 +85,7 @@ module Expedite
|
|
|
85
85
|
## suspend_resume_on_tstp_cont(pid)
|
|
86
86
|
|
|
87
87
|
## forward_signals(application)
|
|
88
|
-
result = agent.recv_object
|
|
88
|
+
result = agent.recv_object(env)
|
|
89
89
|
if result.key?("exception")
|
|
90
90
|
e = result["exception"]
|
|
91
91
|
log "got exception #{e}"
|
|
@@ -106,7 +106,9 @@ module Expedite
|
|
|
106
106
|
def boot_server
|
|
107
107
|
env.socket_path.unlink if env.socket_path.exist?
|
|
108
108
|
|
|
109
|
-
pid
|
|
109
|
+
pid = Bundler.with_original_env do
|
|
110
|
+
Process.spawn(gem_env, env.server_command, out: File::NULL, chdir: env.root)
|
|
111
|
+
end
|
|
110
112
|
timeout = Time.now + BOOT_TIMEOUT
|
|
111
113
|
|
|
112
114
|
@server_booted = true
|
|
@@ -118,9 +120,9 @@ module Expedite
|
|
|
118
120
|
# Server did not start
|
|
119
121
|
raise ArgumentError, "Server exited: #{status.exitstatus}"
|
|
120
122
|
elsif Time.now > timeout
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
exit 1
|
|
123
|
+
raise "Starting Expedite server with `#{env.server_command}` " \
|
|
124
|
+
"timed out after #{BOOT_TIMEOUT} seconds. Was waiting for #{env.socket_path} to appear."
|
|
125
|
+
#exit 1
|
|
124
126
|
end
|
|
125
127
|
|
|
126
128
|
sleep 0.1
|
data/lib/expedite/env.rb
CHANGED
|
@@ -6,19 +6,31 @@ require 'expedite/server/application_manager'
|
|
|
6
6
|
module Expedite
|
|
7
7
|
class Env
|
|
8
8
|
attr_accessor :root
|
|
9
|
-
attr_accessor :application_id, :app_name, :log_file
|
|
9
|
+
attr_accessor :application_id, :app_name, :log_file, :bundler
|
|
10
10
|
attr_reader :applications
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
##
|
|
13
|
+
# The environment containing the target application.
|
|
14
|
+
#
|
|
15
|
+
# The root and app_name are used to derive the socket.
|
|
16
|
+
# @param root [String] Path to the root directory.
|
|
17
|
+
# @param app_name [String] The name of the application.
|
|
18
|
+
# @param log_file [IO] Path to log file. If nil, logs are discarded.
|
|
19
|
+
# @param bundler [Boolean] If true, `bundle exec` will be added in front
|
|
20
|
+
# of the server command. Defaults to true.
|
|
21
|
+
def initialize(root: nil, app_name: nil, log_file: nil, bundler: true)
|
|
22
|
+
# Use realpath so that directories that are symlinked end up with
|
|
23
|
+
# the same root. This is important for getting the correct socket.
|
|
24
|
+
@root = File.realpath(root || Dir.pwd)
|
|
14
25
|
@app_name = app_name || File.basename(@root)
|
|
15
26
|
@log_file = log_file || File.open(File::NULL, "a")
|
|
16
|
-
@
|
|
27
|
+
@bundler = bundler
|
|
17
28
|
|
|
18
|
-
@application_id = Digest::SHA1.hexdigest(@root)
|
|
29
|
+
@application_id = Digest::SHA1.hexdigest(@root + "|" + @app_name)
|
|
30
|
+
@tmp_path = nil
|
|
19
31
|
|
|
20
|
-
|
|
21
|
-
@applications = Server::ApplicationManager.new(
|
|
32
|
+
# TODO: @applications should only be available in the server
|
|
33
|
+
@applications = Server::ApplicationManager.new(self)
|
|
22
34
|
end
|
|
23
35
|
|
|
24
36
|
def version
|
|
@@ -49,7 +61,13 @@ module Expedite
|
|
|
49
61
|
end
|
|
50
62
|
|
|
51
63
|
def server_command
|
|
52
|
-
|
|
64
|
+
bin_expedite = File.expand_path("../../../bin/expedite", __FILE__)
|
|
65
|
+
cmd = if bundler
|
|
66
|
+
"bundle exec #{bin_expedite}"
|
|
67
|
+
else
|
|
68
|
+
bin_expedite
|
|
69
|
+
end
|
|
70
|
+
"#{cmd} server --background"
|
|
53
71
|
end
|
|
54
72
|
|
|
55
73
|
def graceful_termination_timeout
|
data/lib/expedite/errors.rb
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Expedite
|
|
2
|
+
module Hooks
|
|
3
|
+
##
|
|
4
|
+
# Register a new hook with the given block to name
|
|
5
|
+
# @param name [String] Name of the hook
|
|
6
|
+
def register_hook(name, block)
|
|
7
|
+
return clear_hooks(name) if block.nil?
|
|
8
|
+
|
|
9
|
+
block = Array(block)
|
|
10
|
+
all_hooks[name].concat(block)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
# Clears all hooks for the specified name
|
|
15
|
+
# @param name [String] Name of the hook
|
|
16
|
+
def clear_hooks(name)
|
|
17
|
+
all_hooks[name] = []
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# Returns all hooks for the specified name
|
|
22
|
+
# @param name [String] Name of the hook
|
|
23
|
+
def hooks(name)
|
|
24
|
+
all_hooks[name]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# Returne all hooks as a hash
|
|
29
|
+
def all_hooks
|
|
30
|
+
@all_hooks ||= Hash.new { |h, k| h[k] = [] }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
# Runs all Procs registered for the specified name
|
|
35
|
+
# @param name [String] Name of the hook
|
|
36
|
+
# @param @args Arguments passed to the Procs
|
|
37
|
+
def run_hook(name, *args)
|
|
38
|
+
hks = hooks(name)
|
|
39
|
+
return if hks.empty?
|
|
40
|
+
|
|
41
|
+
hks.each do |hook|
|
|
42
|
+
args.any? ? hook.call(*args) : hook.call
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
data/lib/expedite/protocol.rb
CHANGED
|
@@ -8,14 +8,63 @@ module Expedite
|
|
|
8
8
|
|
|
9
9
|
self.puts data.bytesize.to_i
|
|
10
10
|
self.write data
|
|
11
|
+
self.write "$"
|
|
11
12
|
end
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
##
|
|
15
|
+
# Result is an exception
|
|
16
|
+
#
|
|
17
|
+
def send_exception(e, env)
|
|
18
|
+
if !e.is_a?(Expedite::Error)
|
|
19
|
+
ie = Expedite::InvokeError.new("#{e.class}: #{e.message}")
|
|
20
|
+
ie.set_backtrace(e.backtrace)
|
|
21
|
+
e = ie
|
|
22
|
+
end
|
|
23
|
+
self.send_object({"exception" => e}, env)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# Result is a normal return value
|
|
28
|
+
#
|
|
29
|
+
def send_return(obj, env)
|
|
30
|
+
self.send_object({"return" => obj}, env)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def recv_object(env)
|
|
14
34
|
len = self.gets.to_i
|
|
15
35
|
data = self.read(len)
|
|
36
|
+
e = self.read(1)
|
|
37
|
+
env.log "recv_object len=#{len} data=... e=#{e}"
|
|
38
|
+
raise "Unexpected end #{e}" if e != "$"
|
|
16
39
|
Marshal.load(data)
|
|
17
40
|
end
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
##
|
|
44
|
+
# Send sockets for setup.
|
|
45
|
+
# Linux seems to require all fds to be sent first
|
|
46
|
+
#
|
|
47
|
+
def send_setup(child_socket, env)
|
|
48
|
+
self.send_io STDOUT
|
|
49
|
+
self.send_io STDERR
|
|
50
|
+
self.send_io STDIN
|
|
51
|
+
self.send_io env.log_file
|
|
52
|
+
self.send_io child_socket
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
##
|
|
56
|
+
# Receive setup sockets.
|
|
57
|
+
# Returns the child_socket
|
|
58
|
+
#
|
|
59
|
+
def recv_setup(env)
|
|
60
|
+
streams = 5.times.map { self.recv_io }
|
|
61
|
+
[STDOUT, STDERR, STDIN].zip(streams[0..2]).each { |a, b| a.reopen(b) }
|
|
62
|
+
env.log_file = streams[3]
|
|
63
|
+
return streams
|
|
64
|
+
end
|
|
18
65
|
end
|
|
19
66
|
end
|
|
20
67
|
|
|
68
|
+
module ActiveRecord
|
|
69
|
+
end
|
|
21
70
|
IO.include ::Expedite::Protocol
|
|
@@ -4,11 +4,11 @@ require 'pty'
|
|
|
4
4
|
require 'set'
|
|
5
5
|
require 'socket'
|
|
6
6
|
require 'expedite/actions'
|
|
7
|
+
require 'expedite/agents'
|
|
7
8
|
require 'expedite/env'
|
|
8
9
|
require 'expedite/failsafe_thread'
|
|
9
10
|
require 'expedite/protocol'
|
|
10
11
|
require 'expedite/signals'
|
|
11
|
-
require 'expedite/agents'
|
|
12
12
|
|
|
13
13
|
module Expedite
|
|
14
14
|
def self.agent
|
|
@@ -33,11 +33,12 @@ module Expedite
|
|
|
33
33
|
class Agent
|
|
34
34
|
include Signals
|
|
35
35
|
|
|
36
|
-
attr_reader :
|
|
36
|
+
attr_reader :name
|
|
37
37
|
attr_reader :manager, :env
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
# @params name [String] Name of agent
|
|
40
|
+
def initialize(name:, manager:, env:)
|
|
41
|
+
@name = name
|
|
41
42
|
@manager = manager
|
|
42
43
|
@env = env
|
|
43
44
|
@mutex = Mutex.new
|
|
@@ -56,8 +57,8 @@ module Expedite
|
|
|
56
57
|
Signal.trap("TERM") { terminate }
|
|
57
58
|
|
|
58
59
|
env.load_helper
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
|
|
61
|
+
serve
|
|
61
62
|
end
|
|
62
63
|
|
|
63
64
|
def state(val)
|
|
@@ -75,8 +76,12 @@ module Expedite
|
|
|
75
76
|
env.app_name
|
|
76
77
|
end
|
|
77
78
|
|
|
79
|
+
def agent
|
|
80
|
+
@agent ||= Expedite::Agents.lookup(name)
|
|
81
|
+
end
|
|
82
|
+
|
|
78
83
|
def log(message)
|
|
79
|
-
env.log "[application:#{
|
|
84
|
+
env.log "[application:#{name}] #{message}"
|
|
80
85
|
end
|
|
81
86
|
|
|
82
87
|
def preloaded?
|
|
@@ -112,10 +117,10 @@ module Expedite
|
|
|
112
117
|
with_pty { preload }
|
|
113
118
|
end
|
|
114
119
|
|
|
115
|
-
def
|
|
116
|
-
$0 = "expedite agent | #{app_name} | #{
|
|
120
|
+
def serve
|
|
121
|
+
$0 = "expedite agent | #{app_name} | #{name}"
|
|
117
122
|
|
|
118
|
-
|
|
123
|
+
agent.run_hook(:before_serve, name)
|
|
119
124
|
|
|
120
125
|
state :running
|
|
121
126
|
manager.puts
|
|
@@ -124,36 +129,37 @@ module Expedite
|
|
|
124
129
|
IO.select [manager, @interrupt.first]
|
|
125
130
|
|
|
126
131
|
if terminating? || preload_failed?
|
|
132
|
+
agent.run_hook(:after_serve, name)
|
|
127
133
|
exit
|
|
128
134
|
else
|
|
129
|
-
|
|
135
|
+
serve_request(manager.recv_io(UNIXSocket))
|
|
130
136
|
end
|
|
131
137
|
end
|
|
132
138
|
end
|
|
133
139
|
|
|
134
|
-
def
|
|
140
|
+
def serve_request(client)
|
|
135
141
|
puts "got client"
|
|
136
142
|
manager.puts
|
|
137
143
|
|
|
138
|
-
|
|
139
|
-
[STDOUT, STDERR, STDIN].zip(streams).each { |a, b| a.reopen(b) }
|
|
144
|
+
streams = client.recv_setup(env)
|
|
140
145
|
|
|
141
146
|
preload unless preloaded?
|
|
142
147
|
|
|
143
|
-
|
|
144
|
-
log "serve #{
|
|
148
|
+
cargs, cenv, cmethod = client.recv_object(env).values_at("args", "env", "method")
|
|
149
|
+
log "serve #{cargs} using #{cmethod}"
|
|
145
150
|
|
|
146
|
-
exec_name =
|
|
151
|
+
exec_name = cargs.shift
|
|
147
152
|
action = Expedite::Actions.lookup(exec_name)
|
|
148
|
-
action.setup(
|
|
153
|
+
action.setup(streams)
|
|
154
|
+
# TODO: before(:request)
|
|
149
155
|
|
|
150
156
|
connect_database # why are we connecting prior? is this for invoke?
|
|
151
|
-
pid = case
|
|
157
|
+
pid = case cmethod
|
|
152
158
|
when "invoke"
|
|
153
159
|
# TODO: Invoke in a worker process instead of the preloader
|
|
154
|
-
serve_invoke(client, action,
|
|
160
|
+
serve_invoke(client, action, cargs, cenv)
|
|
155
161
|
else
|
|
156
|
-
serve_fork(client, action,
|
|
162
|
+
serve_fork(client, action, cargs, cenv)
|
|
157
163
|
end
|
|
158
164
|
|
|
159
165
|
disconnect_database
|
|
@@ -186,25 +192,25 @@ module Expedite
|
|
|
186
192
|
end
|
|
187
193
|
|
|
188
194
|
# Returns pid of the current process
|
|
189
|
-
def serve_invoke(client, action,
|
|
195
|
+
def serve_invoke(client, action, cargs, cenv)
|
|
190
196
|
begin
|
|
191
|
-
ret = action.call(*
|
|
197
|
+
ret = action.call(*cargs)
|
|
192
198
|
rescue Exception => e
|
|
193
|
-
client.
|
|
199
|
+
client.send_exception(e, self.env)
|
|
194
200
|
else
|
|
195
|
-
client.
|
|
201
|
+
client.send_return(ret, self.env)
|
|
196
202
|
end
|
|
197
203
|
Process.pid
|
|
198
204
|
end
|
|
199
205
|
|
|
200
|
-
def serve_fork(client, action,
|
|
206
|
+
def serve_fork(client, action, cargs, cenv)
|
|
201
207
|
fork do
|
|
202
208
|
Process.setsid
|
|
203
209
|
IGNORE_SIGNALS.each { |sig| trap(sig, "DEFAULT") }
|
|
204
210
|
trap("TERM", "DEFAULT")
|
|
205
211
|
|
|
206
212
|
# Load in the current env vars, except those which *were* changed when Spring started
|
|
207
|
-
|
|
213
|
+
cenv.each { |k, v| ENV[k] = v }
|
|
208
214
|
|
|
209
215
|
# requiring is faster, so if config.cache_classes was true in
|
|
210
216
|
# the environment's config file, then we can respect that from
|
|
@@ -221,11 +227,11 @@ module Expedite
|
|
|
221
227
|
shush_backtraces
|
|
222
228
|
|
|
223
229
|
begin
|
|
224
|
-
ret = action.call(*
|
|
230
|
+
ret = action.call(*cargs)
|
|
225
231
|
rescue => e
|
|
226
|
-
client.
|
|
232
|
+
client.send_exception(e, self.env)
|
|
227
233
|
else
|
|
228
|
-
client.
|
|
234
|
+
client.send_return(ret, self.env)
|
|
229
235
|
end
|
|
230
236
|
end
|
|
231
237
|
end
|
|
@@ -82,7 +82,7 @@ module Expedite
|
|
|
82
82
|
end
|
|
83
83
|
rescue Exception => e
|
|
84
84
|
# NotImplementedError is an Exception, not StandardError
|
|
85
|
-
client.
|
|
85
|
+
client.send_exception(e, env)
|
|
86
86
|
return Process.pid
|
|
87
87
|
rescue Errno::ECONNRESET, Errno::EPIPE => e
|
|
88
88
|
log "#{e} while reading from child; returning no pid"
|
|
@@ -95,9 +95,10 @@ module Expedite
|
|
|
95
95
|
log "stopping"
|
|
96
96
|
@state = :stopping
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
Process.
|
|
98
|
+
_pid = self.pid
|
|
99
|
+
if _pid
|
|
100
|
+
Process.kill('TERM', _pid)
|
|
101
|
+
Process.wait(_pid)
|
|
101
102
|
end
|
|
102
103
|
rescue Errno::ESRCH, Errno::ECHILD
|
|
103
104
|
# Don't care
|
|
@@ -123,30 +124,31 @@ module Expedite
|
|
|
123
124
|
|
|
124
125
|
# Creates a child that is forked from a parent
|
|
125
126
|
def fork_child(preload = false)
|
|
126
|
-
|
|
127
|
+
child_socket = nil
|
|
128
|
+
wr = nil
|
|
129
|
+
begin
|
|
130
|
+
@child, child_socket = UNIXSocket.pair(:STREAM)
|
|
127
131
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
wr.send_io STDOUT
|
|
131
|
-
wr.send_io STDERR
|
|
132
|
-
wr.send_io STDIN
|
|
132
|
+
# Compose command
|
|
133
|
+
wr, rd = UNIXSocket.pair(:STREAM)
|
|
133
134
|
|
|
134
|
-
|
|
135
|
-
'args' => ['expedite/boot', name],
|
|
136
|
-
'env' => {},
|
|
137
|
-
'method' => "fork",
|
|
138
|
-
}, env)
|
|
135
|
+
wr.send_setup(child_socket, env)
|
|
139
136
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
137
|
+
wr.send_object({
|
|
138
|
+
'args' => ['expedite/boot', name],
|
|
139
|
+
'env' => {},
|
|
140
|
+
'method' => "fork",
|
|
141
|
+
}, env)
|
|
143
142
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
@pid = env.applications.with(parent) do |target|
|
|
144
|
+
target.run(rd)
|
|
145
|
+
end
|
|
147
146
|
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
start_wait_thread(pid, child) if child.gets
|
|
148
|
+
ensure
|
|
149
|
+
wr&.close
|
|
150
|
+
child_socket&.close
|
|
151
|
+
end
|
|
150
152
|
end
|
|
151
153
|
|
|
152
154
|
# Creates a child that is started from scratch
|
|
@@ -7,6 +7,9 @@ require "expedite/signals"
|
|
|
7
7
|
|
|
8
8
|
module Expedite
|
|
9
9
|
module Server
|
|
10
|
+
##
|
|
11
|
+
# Controls the `expedite server`.
|
|
12
|
+
#
|
|
10
13
|
class Controller
|
|
11
14
|
include Signals
|
|
12
15
|
|
|
@@ -99,7 +102,7 @@ module Expedite
|
|
|
99
102
|
|
|
100
103
|
# Corresponds to Client::Invoke#connect_to_agent
|
|
101
104
|
app_client = client.recv_io
|
|
102
|
-
command = client.recv_object
|
|
105
|
+
command = client.recv_object(env)
|
|
103
106
|
|
|
104
107
|
args, agent = command.values_at("args", "agent")
|
|
105
108
|
cmd = args.first
|
|
@@ -111,9 +114,7 @@ module Expedite
|
|
|
111
114
|
client.puts
|
|
112
115
|
|
|
113
116
|
unix_socket = UNIXSocket.for_fd(app_client.fileno)
|
|
114
|
-
|
|
115
|
-
_stderr = unix_socket.recv_io
|
|
116
|
-
_stdin = unix_socket.recv_io
|
|
117
|
+
_ = unix_socket.recv_setup(env)
|
|
117
118
|
|
|
118
119
|
client.puts Process.pid
|
|
119
120
|
|
|
@@ -121,7 +122,7 @@ module Expedite
|
|
|
121
122
|
env.applications.pools.each do |k, pool|
|
|
122
123
|
application_pids.concat(pool.all.map(&:pid))
|
|
123
124
|
end
|
|
124
|
-
unix_socket.
|
|
125
|
+
unix_socket.send_return(application_pids, env)
|
|
125
126
|
|
|
126
127
|
unix_socket.close
|
|
127
128
|
client.close
|
|
@@ -139,18 +140,16 @@ module Expedite
|
|
|
139
140
|
end
|
|
140
141
|
rescue AgentNotFoundError => e
|
|
141
142
|
unix_socket = UNIXSocket.for_fd(app_client.fileno)
|
|
142
|
-
|
|
143
|
-
_stderr = unix_socket.recv_io
|
|
144
|
-
_stdin = unix_socket.recv_io
|
|
143
|
+
_ = unix_socket.recv_setup(env)
|
|
145
144
|
|
|
146
|
-
args, env = unix_socket.recv_object.values_at("args", "env")
|
|
145
|
+
args, env = unix_socket.recv_object(env).values_at("args", "env")
|
|
147
146
|
|
|
148
147
|
client.puts Process.pid
|
|
149
148
|
|
|
150
149
|
# boot only
|
|
151
150
|
#@child_socket = client.recv_io
|
|
152
151
|
#@log_file = client.recv_io
|
|
153
|
-
unix_socket.
|
|
152
|
+
unix_socket.send_exception(e, env)
|
|
154
153
|
|
|
155
154
|
unix_socket.close
|
|
156
155
|
client.close
|
data/lib/expedite/syntax.rb
CHANGED
|
@@ -13,7 +13,9 @@ module Expedite
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def agent(name, parent:nil, &block)
|
|
16
|
-
Expedite::Agents.register(name, parent: parent
|
|
16
|
+
agent = Expedite::Agents.register(name, parent: parent)
|
|
17
|
+
agent.instance_eval(&block) if !block.nil?
|
|
18
|
+
agent
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
def self.run(&block)
|
|
@@ -23,4 +25,4 @@ module Expedite
|
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
extend Syntax
|
|
26
|
-
end
|
|
28
|
+
end
|
data/lib/expedite/version.rb
CHANGED
data/lib/expedite.rb
CHANGED
|
@@ -1,33 +1,14 @@
|
|
|
1
|
-
require 'expedite/client/
|
|
2
|
-
require 'expedite/client/invoke'
|
|
1
|
+
require 'expedite/client/agent_proxy'
|
|
3
2
|
require 'expedite/syntax'
|
|
4
3
|
|
|
5
|
-
module Expedite
|
|
6
|
-
class AgentProxy
|
|
7
|
-
attr_accessor :env, :agent
|
|
8
|
-
|
|
9
|
-
def initialize(env:, agent:)
|
|
10
|
-
self.env = env
|
|
11
|
-
self.agent = agent
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def exec(*args)
|
|
15
|
-
Client::Exec.new(env: env, agent: agent).call(*args)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def invoke(*args)
|
|
19
|
-
Client::Invoke.new(env: env, agent: agent).call(*args)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
4
|
|
|
24
5
|
module Expedite
|
|
25
6
|
##
|
|
26
7
|
# Returns a client to dispatch actions to the specified agent
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
8
|
+
# @param name [String] Name of the agent that we want to talk to
|
|
9
|
+
# @param env [Expedite::Env] Defaults to an environment pointing to the
|
|
10
|
+
# current directory
|
|
11
|
+
def self.agent(name, env: Env.new)
|
|
12
|
+
Client::AgentProxy.new(name, env: env)
|
|
32
13
|
end
|
|
33
14
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: expedite
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bing-Chang Lai
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2023-02-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Manages Ruby processes that can be used to spawn child processes faster.
|
|
14
14
|
email: johnny.lai@me.com
|
|
@@ -29,6 +29,7 @@ files:
|
|
|
29
29
|
- lib/expedite/cli/server.rb
|
|
30
30
|
- lib/expedite/cli/status.rb
|
|
31
31
|
- lib/expedite/cli/stop.rb
|
|
32
|
+
- lib/expedite/client/agent_proxy.rb
|
|
32
33
|
- lib/expedite/client/base.rb
|
|
33
34
|
- lib/expedite/client/exec.rb
|
|
34
35
|
- lib/expedite/client/invoke.rb
|
|
@@ -36,6 +37,7 @@ files:
|
|
|
36
37
|
- lib/expedite/errors.rb
|
|
37
38
|
- lib/expedite/failsafe_thread.rb
|
|
38
39
|
- lib/expedite/helper/rails.rb
|
|
40
|
+
- lib/expedite/hooks.rb
|
|
39
41
|
- lib/expedite/protocol.rb
|
|
40
42
|
- lib/expedite/server/agent.rb
|
|
41
43
|
- lib/expedite/server/agent_boot.rb
|
|
@@ -65,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
65
67
|
- !ruby/object:Gem::Version
|
|
66
68
|
version: '0'
|
|
67
69
|
requirements: []
|
|
68
|
-
rubygems_version: 3.
|
|
70
|
+
rubygems_version: 3.4.1
|
|
69
71
|
signing_key:
|
|
70
72
|
specification_version: 4
|
|
71
73
|
summary: Expedite startup of Ruby process
|