fate 0.2.20 → 0.3.0
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/bin/fate +7 -8
- data/lib/fate.rb +43 -80
- data/lib/fate/process_manager.rb +47 -28
- data/lib/fate/repl.rb +50 -35
- data/lib/fate/service.rb +13 -0
- metadata +2 -2
data/bin/fate
CHANGED
@@ -12,14 +12,14 @@ $LOAD_PATH.unshift("#{FATE_ROOT}/lib")
|
|
12
12
|
require "fate"
|
13
13
|
|
14
14
|
options = {
|
15
|
-
:
|
15
|
+
:specification => "fate.json",
|
16
16
|
:default_log => STDOUT
|
17
17
|
}
|
18
18
|
|
19
19
|
# TODO: config file flag
|
20
20
|
OptionParser.new do |parser|
|
21
21
|
parser.on("-c", "--configuration=FILE", "The origin of the events") do |file|
|
22
|
-
options[:
|
22
|
+
options[:specification] = file
|
23
23
|
end
|
24
24
|
parser.on("-l", "--log=FILE", "Processes log to FILE") do |file|
|
25
25
|
options[:default_log] = File.new(file, "a")
|
@@ -27,14 +27,13 @@ OptionParser.new do |parser|
|
|
27
27
|
end.parse!
|
28
28
|
|
29
29
|
|
30
|
-
string = File.read(options[:
|
31
|
-
|
32
|
-
fate = Fate.new(configuration, options)
|
33
|
-
|
30
|
+
string = File.read(options[:specification])
|
31
|
+
specification = JSON.parse(string, :symbolize_names => true)
|
34
32
|
|
33
|
+
fate = Fate.new(specification, options)
|
35
34
|
|
36
35
|
require "fate/repl"
|
37
|
-
fate.start(ARGV)
|
38
|
-
fate.repl
|
36
|
+
fate.control.start(*ARGV)
|
37
|
+
fate.control.repl
|
39
38
|
|
40
39
|
|
data/lib/fate.rb
CHANGED
@@ -13,104 +13,67 @@ class Fate
|
|
13
13
|
self.new(specification).start(&block)
|
14
14
|
end
|
15
15
|
|
16
|
-
attr_reader :service, :manager, :
|
16
|
+
attr_reader :service, :manager, :control
|
17
|
+
def initialize(specification, options)
|
18
|
+
@service = Fate::Service.new(specification, options)
|
19
|
+
@manager = Fate::ProcessManager.new(service, options)
|
20
|
+
@control = Fate::Control.new(@manager, options)
|
21
|
+
end
|
17
22
|
|
18
|
-
|
19
|
-
@service = Service.new(spec, options)
|
20
|
-
@completions = @service.completions
|
23
|
+
class Control
|
21
24
|
|
22
|
-
|
23
|
-
@logger = @service.logger["Fate Control"]
|
25
|
+
attr_reader :service, :manager, :completions, :logger
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
+
def initialize(manager, options={})
|
28
|
+
@manager = manager
|
29
|
+
@service = @manager.service
|
30
|
+
@completions = @service.completions
|
27
31
|
|
28
|
-
|
29
|
-
|
30
|
-
|
32
|
+
@spec = @service.specification
|
33
|
+
@logger = @service.logger["Fate Control"]
|
34
|
+
end
|
31
35
|
|
32
|
-
|
33
|
-
|
34
|
-
if block
|
35
|
-
yield(self)
|
36
|
-
stop
|
37
|
-
end
|
38
|
-
else
|
39
|
-
logger.error "Failed to start"
|
36
|
+
def log(*args, &block)
|
37
|
+
@logger.log(*args, &block)
|
40
38
|
end
|
41
|
-
end
|
42
39
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
self.start_command(command_spec)
|
47
|
-
end
|
48
|
-
else
|
49
|
-
if manager.start_group(@service.commands)
|
50
|
-
logger.green "All commands are running."
|
51
|
-
true
|
40
|
+
def start(*command_strings)
|
41
|
+
if manager.start(command_strings)
|
42
|
+
logger.green "All processes are running."
|
52
43
|
else
|
53
|
-
|
44
|
+
logger.error "Failed to start."
|
54
45
|
end
|
55
46
|
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def stop
|
59
|
-
manager.stop_all
|
60
|
-
end
|
61
47
|
|
62
|
-
|
63
|
-
|
64
|
-
start
|
65
|
-
end
|
66
|
-
|
67
|
-
def start_command(command_spec)
|
68
|
-
names = @service.resolve_commands(command_spec)
|
69
|
-
if names.empty?
|
70
|
-
puts "No commands found for: #{command_spec}"
|
71
|
-
else
|
72
|
-
commands = {}
|
73
|
-
names.each do |name|
|
74
|
-
command = @service.commands[name]
|
75
|
-
commands[name] = command
|
76
|
-
end
|
77
|
-
if manager.start_group(commands)
|
78
|
-
logger.green "All commands in '#{command_spec}' running."
|
79
|
-
else
|
80
|
-
logger.error "Failed to start '#{command_spec}'."
|
81
|
-
end
|
48
|
+
def stop(*command_strings)
|
49
|
+
manager.stop(command_strings)
|
82
50
|
end
|
83
|
-
end
|
84
51
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
puts "No commands found for: #{command_spec}"
|
89
|
-
else
|
90
|
-
names.each do |name|
|
91
|
-
manager.stop_command(name)
|
92
|
-
end
|
52
|
+
def restart(*command_strings)
|
53
|
+
stop(command_strings)
|
54
|
+
start(command_strings)
|
93
55
|
end
|
94
|
-
end
|
95
56
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
57
|
+
# Run only the processes specified by the arguments. Any existing
|
58
|
+
# processes outside this set will be stopped.
|
59
|
+
def run(*command_strings)
|
60
|
+
manager.run(command_strings)
|
61
|
+
end
|
100
62
|
|
101
|
-
|
102
|
-
|
103
|
-
|
63
|
+
def running
|
64
|
+
manager.running
|
65
|
+
end
|
104
66
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
67
|
+
# ad hoc shell out, with rescuing because of some apparent bugs
|
68
|
+
# in MRI 1.8.7's ability to cope with unusual exit codes.
|
69
|
+
def system(command)
|
70
|
+
begin
|
71
|
+
Kernel.system command
|
72
|
+
rescue => error
|
73
|
+
puts "Exception raised when executing '#{command}': #{error.inspect}"
|
74
|
+
end
|
112
75
|
end
|
113
|
-
end
|
114
76
|
|
77
|
+
end
|
115
78
|
end
|
116
79
|
|
data/lib/fate/process_manager.rb
CHANGED
@@ -6,7 +6,7 @@ class Fate
|
|
6
6
|
# processes, tracking them by name, and handling unexpected exits and signals.
|
7
7
|
class ProcessManager
|
8
8
|
|
9
|
-
attr_reader :logger, :output_handlers
|
9
|
+
attr_reader :logger, :output_handlers, :service
|
10
10
|
def initialize(service, options={})
|
11
11
|
@directory = options[:directory]
|
12
12
|
@mutex = Mutex.new
|
@@ -19,32 +19,66 @@ class Fate
|
|
19
19
|
@names_by_pid = {}
|
20
20
|
@pids_by_name = {}
|
21
21
|
at_exit do
|
22
|
-
|
22
|
+
stop_group(running)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
26
|
+
def run(command_strings=[])
|
27
|
+
if command_strings.empty?
|
28
|
+
run(@service.commands.keys)
|
29
|
+
else
|
30
|
+
commands = @service.resolve(command_strings)
|
31
|
+
# don't need to start processes that are already running
|
32
|
+
noop = commands & running
|
33
|
+
to_start = commands - noop
|
34
|
+
to_stop = running - commands
|
35
|
+
|
36
|
+
stop_group(to_stop)
|
37
|
+
start_group(to_start)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def start(command_strings=[])
|
42
|
+
if command_strings.empty?
|
43
|
+
start_group(@service.commands.keys)
|
44
|
+
else
|
45
|
+
commands = @service.resolve(command_strings)
|
46
|
+
start_group(commands)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def stop(command_strings=[])
|
51
|
+
if command_strings.empty?
|
52
|
+
stop_group(running)
|
53
|
+
else
|
54
|
+
names = @service.resolve(command_strings)
|
55
|
+
stop_group(names)
|
32
56
|
end
|
33
57
|
end
|
34
58
|
|
35
|
-
def start_group(
|
36
|
-
|
59
|
+
def start_group(names)
|
60
|
+
ordered = @service.start_order(names)
|
61
|
+
ordered.each do |name|
|
62
|
+
command = service.commands[name]
|
37
63
|
@commands_by_name[name] = command
|
38
64
|
start_command(name, command) unless @down_in_flames
|
39
65
|
end
|
40
|
-
|
41
|
-
until hash.keys.all? { |key| @threads[key] }
|
66
|
+
until names.all? { |name| @threads[name] }
|
42
67
|
return false if @down_in_flames
|
43
68
|
sleep 0.1
|
44
69
|
end
|
45
70
|
return true
|
46
71
|
end
|
47
72
|
|
73
|
+
def stop_group(names)
|
74
|
+
@mutex.synchronize do
|
75
|
+
ordered = @service.stop_order(names)
|
76
|
+
ordered.each do |name|
|
77
|
+
term(name)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
48
82
|
def start_command(name, command)
|
49
83
|
if pid = @pids_by_name[name]
|
50
84
|
logger.warn "'#{name}' is already running with pid #{pid}"
|
@@ -53,10 +87,6 @@ class Fate
|
|
53
87
|
end
|
54
88
|
end
|
55
89
|
|
56
|
-
def stop_command(name)
|
57
|
-
term(name)
|
58
|
-
end
|
59
|
-
|
60
90
|
def term(name)
|
61
91
|
if pid = @pids_by_name[name]
|
62
92
|
@names_by_pid.delete(pid)
|
@@ -164,22 +194,11 @@ class Fate
|
|
164
194
|
end
|
165
195
|
logger.info "Shutting down all processes."
|
166
196
|
|
167
|
-
|
197
|
+
stop_group(running)
|
168
198
|
exit(1)
|
169
199
|
end
|
170
200
|
|
171
201
|
|
172
|
-
# ad hoc shell out, with rescuing because of some apparent bugs
|
173
|
-
# in MRI 1.8.7's ability to cope with unusual exit codes.
|
174
|
-
def system(command)
|
175
|
-
#begin
|
176
|
-
Kernel.system command
|
177
|
-
#rescue => error
|
178
|
-
#puts "Exception raised when executing '#{command}': #{error.inspect}"
|
179
|
-
#end
|
180
|
-
end
|
181
|
-
|
182
|
-
|
183
202
|
|
184
203
|
end
|
185
204
|
end
|
data/lib/fate/repl.rb
CHANGED
@@ -1,53 +1,68 @@
|
|
1
1
|
require "harp"
|
2
2
|
class Fate
|
3
|
+
class Control
|
3
4
|
|
4
|
-
|
5
|
+
include Harp
|
5
6
|
|
6
|
-
|
7
|
+
setup_harp do |harp|
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
command("help") do
|
10
|
+
commands = harp.command_names.select {|c| c.size > 1 } + ["!"]
|
11
|
+
puts "* Available commands: " << commands.sort.join(" ")
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
command("quit", :alias => "q") { exit }
|
15
|
+
command("exit") { exit }
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
command("stop") do
|
18
|
+
self.stop
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
command("stop", :process_name) do |args|
|
22
|
+
command = args.first
|
23
|
+
self.stop(args.first)
|
24
|
+
end
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
26
|
+
command("run") do
|
27
|
+
self.run
|
28
|
+
end
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
command("run", :process_name) do |args|
|
31
|
+
command = args.first
|
32
|
+
self.run(args.first)
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
command("start", :process_name) do |args|
|
36
|
+
command = args.first
|
37
|
+
self.start(args.first)
|
38
|
+
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
command("restart") do
|
41
|
+
self.restart
|
42
|
+
end
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
44
|
+
command("restart", :process_name) do |args|
|
45
|
+
command = args.first
|
46
|
+
self.restart(args.first)
|
47
|
+
end
|
48
|
+
|
49
|
+
command("processes") do
|
50
|
+
puts self.service.names
|
51
|
+
end
|
52
|
+
|
53
|
+
#command("groups") do
|
54
|
+
#end
|
55
|
+
|
56
|
+
command("running") do
|
57
|
+
puts self.running
|
58
|
+
end
|
59
|
+
|
60
|
+
command("configuration") do
|
61
|
+
puts JSON.pretty_generate(self.service.specification)
|
62
|
+
end
|
46
63
|
|
47
|
-
command("configuration") do
|
48
|
-
puts JSON.pretty_generate(self.service.specification)
|
49
64
|
end
|
50
65
|
|
51
66
|
end
|
52
|
-
|
53
67
|
end
|
68
|
+
|
data/lib/fate/service.rb
CHANGED
@@ -95,6 +95,19 @@ class Fate
|
|
95
95
|
out
|
96
96
|
end
|
97
97
|
|
98
|
+
def resolve(specs)
|
99
|
+
command_names = []
|
100
|
+
specs.each do |spec|
|
101
|
+
names = resolve_commands(spec)
|
102
|
+
if names.empty?
|
103
|
+
logger.warn "Fate", "No commands found for: #{spec}"
|
104
|
+
else
|
105
|
+
command_names.concat(names)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
names = command_names.uniq
|
109
|
+
end
|
110
|
+
|
98
111
|
def resolve_commands(name)
|
99
112
|
targets = []
|
100
113
|
if @commands.has_key?(name)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-04-
|
12
|
+
date: 2013-04-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|