service_skeleton 0.0.0.34.g4f6fdb0 → 0.0.0.49.g47046b9
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 +260 -145
- data/lib/service_skeleton.rb +22 -186
- data/lib/service_skeleton/config.rb +57 -30
- data/lib/service_skeleton/config_class.rb +16 -0
- data/lib/service_skeleton/config_variable.rb +24 -16
- data/lib/service_skeleton/config_variable/boolean.rb +21 -0
- data/lib/service_skeleton/config_variable/enum.rb +27 -0
- data/lib/service_skeleton/config_variable/float.rb +25 -0
- data/lib/service_skeleton/config_variable/integer.rb +25 -0
- data/lib/service_skeleton/config_variable/kv_list.rb +26 -0
- data/lib/service_skeleton/config_variable/path_list.rb +13 -0
- data/lib/service_skeleton/config_variable/string.rb +18 -0
- data/lib/service_skeleton/config_variable/url.rb +36 -0
- data/lib/service_skeleton/config_variable/yaml_file.rb +42 -0
- data/lib/service_skeleton/config_variables.rb +49 -82
- data/lib/service_skeleton/error.rb +5 -3
- data/lib/service_skeleton/filtering_logger.rb +2 -0
- data/lib/service_skeleton/generator.rb +165 -0
- data/lib/service_skeleton/logging_helpers.rb +5 -3
- data/lib/service_skeleton/metric_method_name.rb +9 -0
- data/lib/service_skeleton/metrics_methods.rb +28 -13
- data/lib/service_skeleton/runner.rb +46 -0
- data/lib/service_skeleton/service_name.rb +20 -0
- data/lib/service_skeleton/signal_manager.rb +202 -0
- data/lib/service_skeleton/signals_methods.rb +15 -0
- data/lib/service_skeleton/ultravisor_children.rb +17 -0
- data/lib/service_skeleton/ultravisor_loggerstash.rb +11 -0
- data/service_skeleton.gemspec +8 -7
- metadata +65 -15
- data/lib/service_skeleton/background_worker.rb +0 -94
- data/lib/service_skeleton/signal_handler.rb +0 -195
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "service_skeleton/config_variable"
|
4
|
+
|
5
|
+
class ServiceSkeleton::ConfigVariable::Enum < ServiceSkeleton::ConfigVariable
|
6
|
+
private
|
7
|
+
|
8
|
+
def pluck_value(env)
|
9
|
+
maybe_default(env) do
|
10
|
+
v = env[@name.to_s]
|
11
|
+
|
12
|
+
if @opts[:values].is_a?(Array)
|
13
|
+
unless @opts[:values].include?(v)
|
14
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
15
|
+
"Invalid value for #{@name}; must be one of #{@opts[:values].join(", ")}"
|
16
|
+
end
|
17
|
+
v
|
18
|
+
elsif @opts[:values].is_a?(Hash)
|
19
|
+
unless @opts[:values].keys.include?(v)
|
20
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
21
|
+
"Invalid value for #{@name}; must be one of #{@opts[:values].keys.join(", ")}"
|
22
|
+
end
|
23
|
+
@opts[:values][v]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "service_skeleton/config_variable"
|
4
|
+
|
5
|
+
class ServiceSkeleton::ConfigVariable::Float < ServiceSkeleton::ConfigVariable
|
6
|
+
private
|
7
|
+
|
8
|
+
def pluck_value(env)
|
9
|
+
maybe_default(env) do
|
10
|
+
value = env[@name.to_s]
|
11
|
+
|
12
|
+
if value =~ /\A-?\d+.?\d*\z/
|
13
|
+
value.to_f.tap do |f|
|
14
|
+
unless @opts[:range].include?(f)
|
15
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
16
|
+
"Value #{f} for environment variable #{@name} is out of the valid range (must be between #{@opts[:range].first} and #{@opts[:range].last} inclusive)"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
else
|
20
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
21
|
+
"Value #{value.inspect} for environment variable #{@name} is not a valid numeric value"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "service_skeleton/config_variable"
|
4
|
+
|
5
|
+
class ServiceSkeleton::ConfigVariable::Integer < ServiceSkeleton::ConfigVariable
|
6
|
+
private
|
7
|
+
|
8
|
+
def pluck_value(env)
|
9
|
+
maybe_default(env) do
|
10
|
+
value = env[@name.to_s]
|
11
|
+
|
12
|
+
if value =~ /\A-?\d+\z/
|
13
|
+
value.to_i.tap do |i|
|
14
|
+
unless @opts[:range].include?(i)
|
15
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
16
|
+
"Value #{i} for environment variable #{@name} is out of the valid range (must be between #{@opts[:range].first} and #{@opts[:range].last} inclusive)"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
else
|
20
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
21
|
+
"Value #{value.inspect} for environment variable #{@name} is not a valid integer value"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "service_skeleton/config_variable"
|
4
|
+
|
5
|
+
class ServiceSkeleton::ConfigVariable::KVList < ServiceSkeleton::ConfigVariable
|
6
|
+
def redact!(env)
|
7
|
+
env.keys.each { |k| env[k] = "*SENSITIVE*" if k =~ @opts[:key_pattern] }
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def pluck_value(env)
|
13
|
+
matches = env.select { |k, _| k.to_s =~ @opts[:key_pattern] }
|
14
|
+
|
15
|
+
if matches.empty?
|
16
|
+
if @opts.has_key?(:default)
|
17
|
+
@opts[:default]
|
18
|
+
else
|
19
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
20
|
+
"no keys for key-value list #{@name} specified"
|
21
|
+
end
|
22
|
+
else
|
23
|
+
matches.transform_keys { |k| @opts[:key_pattern].match(k.to_s)[1].to_sym }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "service_skeleton/config_variable"
|
4
|
+
|
5
|
+
class ServiceSkeleton::ConfigVariable::PathList < ServiceSkeleton::ConfigVariable
|
6
|
+
private
|
7
|
+
|
8
|
+
def pluck_value(env)
|
9
|
+
maybe_default(env) do
|
10
|
+
env[@name.to_s].split(":")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "service_skeleton/config_variable"
|
4
|
+
|
5
|
+
class ServiceSkeleton::ConfigVariable::String < ServiceSkeleton::ConfigVariable
|
6
|
+
private
|
7
|
+
|
8
|
+
def pluck_value(env)
|
9
|
+
maybe_default(env) do
|
10
|
+
env[@name.to_s].tap do |s|
|
11
|
+
if @opts[:match] && s !~ @opts[:match]
|
12
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
13
|
+
"Value for #{@name} must match #{@opts[:match]}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "service_skeleton/config_variable"
|
4
|
+
|
5
|
+
class ServiceSkeleton::ConfigVariable::URL < ServiceSkeleton::ConfigVariable
|
6
|
+
def redact?(env)
|
7
|
+
!!(env.has_key?(@name.to_s) && (@opts[:sensitive] || URI(env[@name.to_s] || "").password))
|
8
|
+
end
|
9
|
+
|
10
|
+
def redact!(env)
|
11
|
+
if env.has_key?(@name.to_s)
|
12
|
+
super
|
13
|
+
uri = URI(env[@name.to_s])
|
14
|
+
if uri.password
|
15
|
+
uri.password = "*REDACTED*"
|
16
|
+
env[@name.to_s] = uri.to_s
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def pluck_value(env)
|
24
|
+
maybe_default(env) do
|
25
|
+
begin
|
26
|
+
v = env[@name.to_s]
|
27
|
+
URI(v)
|
28
|
+
rescue URI::InvalidURIError
|
29
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
30
|
+
"Value for #{@name} (#{v}) does not appear to be a valid URL"
|
31
|
+
end
|
32
|
+
|
33
|
+
v
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "yaml"
|
4
|
+
|
5
|
+
require "service_skeleton/config_variable"
|
6
|
+
|
7
|
+
class ServiceSkeleton::ConfigVariable::YamlFile < ServiceSkeleton::ConfigVariable
|
8
|
+
def redact!(env)
|
9
|
+
if env.has_key?(@name.to_s)
|
10
|
+
if File.world_readable?(env[@name.to_s])
|
11
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
12
|
+
"Sensitive file #{env[@name.to_s]} is world-readable!"
|
13
|
+
end
|
14
|
+
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def pluck_value(env)
|
22
|
+
maybe_default(env) do
|
23
|
+
begin
|
24
|
+
val = YAML.safe_load(File.read(env[@name.to_s]))
|
25
|
+
if @opts[:klass]
|
26
|
+
val = @opts[:klass].new(val)
|
27
|
+
end
|
28
|
+
|
29
|
+
val
|
30
|
+
rescue Errno::ENOENT
|
31
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
32
|
+
"YAML file #{env[@name.to_s]} does not exist"
|
33
|
+
rescue Errno::EPERM
|
34
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
35
|
+
"Do not have permission to read YAML file #{env[@name.to_s]}"
|
36
|
+
rescue Psych::SyntaxError => ex
|
37
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
38
|
+
"Invalid YAML syntax: #{ex.message}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,112 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative "./error"
|
2
4
|
|
3
5
|
require "service_skeleton/config_variable"
|
4
6
|
|
5
|
-
|
7
|
+
module ServiceSkeleton
|
6
8
|
module ConfigVariables
|
7
|
-
|
8
|
-
|
9
|
-
UNDEFINED = Class.new
|
9
|
+
UNDEFINED = Module.new
|
10
10
|
private_constant :UNDEFINED
|
11
11
|
|
12
|
-
def
|
12
|
+
def registered_variables
|
13
13
|
@registered_variables ||= []
|
14
|
-
|
15
|
-
@registered_variables << ServiceSkeleton::ConfigVariable.new(name, **opts, &callback)
|
16
14
|
end
|
17
15
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
value
|
22
|
-
end
|
16
|
+
def register_variable(name, klass, **opts)
|
17
|
+
if opts[:default] == UNDEFINED
|
18
|
+
opts.delete(:default)
|
23
19
|
end
|
20
|
+
|
21
|
+
registered_variables << {
|
22
|
+
name: name,
|
23
|
+
class: klass,
|
24
|
+
opts: opts,
|
25
|
+
}
|
24
26
|
end
|
25
27
|
|
26
28
|
def boolean(var_name, default: UNDEFINED, sensitive: false)
|
27
|
-
register_variable(var_name, sensitive: sensitive)
|
28
|
-
maybe_default(value, default, var_name) do
|
29
|
-
case value
|
30
|
-
when /\A(no|n|off|0|false)\z/i
|
31
|
-
false
|
32
|
-
when /\A(yes|y|on|1|true)\z/i
|
33
|
-
true
|
34
|
-
else
|
35
|
-
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
36
|
-
"Value #{value.inspect} for environment variable #{var_name} is not a valid boolean value"
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
29
|
+
register_variable(var_name, ConfigVariable::Boolean, default: default, sensitive: sensitive)
|
40
30
|
end
|
41
31
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
value.to_i.tap do |i|
|
47
|
-
unless range.include?(i)
|
48
|
-
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
49
|
-
"Value #{i} for environment variable #{var_name} is out of the valid range (must be between #{range.first} and #{range.last} inclusive)"
|
50
|
-
end
|
51
|
-
end
|
52
|
-
else
|
53
|
-
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
54
|
-
"Value #{value.inspect} for environment variable #{var_name} is not a valid integer value"
|
55
|
-
end
|
56
|
-
end
|
32
|
+
def enum(var_name, values:, default: UNDEFINED, sensitive: false)
|
33
|
+
unless values.is_a?(Hash) || values.is_a?(Array)
|
34
|
+
raise ArgumentError,
|
35
|
+
"values option to enum must be a hash or array"
|
57
36
|
end
|
37
|
+
|
38
|
+
register_variable(var_name, ConfigVariable::Enum, default: default, sensitive: sensitive, values: values)
|
58
39
|
end
|
59
40
|
|
60
41
|
def float(var_name, default: UNDEFINED, sensitive: false, range: -Float::INFINITY..Float::INFINITY)
|
61
|
-
register_variable(var_name, sensitive: sensitive
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
else
|
71
|
-
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
72
|
-
"Value #{value.inspect} for environment variable #{var_name} is not a valid numeric value"
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
42
|
+
register_variable(var_name, ConfigVariable::Float, default: default, sensitive: sensitive, range: range)
|
43
|
+
end
|
44
|
+
|
45
|
+
def integer(var_name, default: UNDEFINED, sensitive: false, range: -Float::INFINITY..Float::INFINITY)
|
46
|
+
register_variable(var_name, ConfigVariable::Integer, default: default, sensitive: sensitive, range: range)
|
47
|
+
end
|
48
|
+
|
49
|
+
def kv_list(var_name, default: UNDEFINED, sensitive: false, key_pattern: /\A#{var_name}_(.*)\z/)
|
50
|
+
register_variable(var_name, ConfigVariable::KVList, default: default, sensitive: sensitive, key_pattern: key_pattern)
|
76
51
|
end
|
77
52
|
|
78
53
|
def path_list(var_name, default: UNDEFINED, sensitive: false)
|
79
|
-
register_variable(var_name, sensitive: sensitive)
|
80
|
-
maybe_default(value, default, var_name) do
|
81
|
-
value.split(":")
|
82
|
-
end
|
83
|
-
end
|
54
|
+
register_variable(var_name, ConfigVariable::PathList, default: default, sensitive: sensitive)
|
84
55
|
end
|
85
56
|
|
86
|
-
def
|
87
|
-
|
88
|
-
register_variable(var_name, sensitive: sensitive, key_pattern: key_pattern) do |matches|
|
89
|
-
maybe_default(matches, default, var_name) do
|
90
|
-
matches.transform_keys do |k|
|
91
|
-
key_pattern.match(k)[1].to_sym
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
57
|
+
def string(var_name, default: UNDEFINED, sensitive: false, match: nil)
|
58
|
+
register_variable(var_name, ConfigVariable::String, default: default, sensitive: sensitive, match: match)
|
95
59
|
end
|
96
60
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
"Value for required environment variable #{var_name} not specified"
|
104
|
-
else
|
105
|
-
default
|
106
|
-
end
|
107
|
-
else
|
108
|
-
yield
|
109
|
-
end
|
61
|
+
def url(var_name, default: UNDEFINED, sensitive: false)
|
62
|
+
register_variable(var_name, ConfigVariable::URL, default: default, sensitive: sensitive)
|
63
|
+
end
|
64
|
+
|
65
|
+
def yaml_file(var_name, default: UNDEFINED, sensitive: false, klass: nil)
|
66
|
+
register_variable(var_name, ConfigVariable::YamlFile, default: default, sensitive: sensitive, klass: klass)
|
110
67
|
end
|
111
68
|
end
|
112
69
|
end
|
70
|
+
|
71
|
+
require_relative "config_variable/boolean"
|
72
|
+
require_relative "config_variable/enum"
|
73
|
+
require_relative "config_variable/float"
|
74
|
+
require_relative "config_variable/integer"
|
75
|
+
require_relative "config_variable/kv_list"
|
76
|
+
require_relative "config_variable/path_list"
|
77
|
+
require_relative "config_variable/string"
|
78
|
+
require_relative "config_variable/url"
|
79
|
+
require_relative "config_variable/yaml_file"
|
@@ -1,8 +1,10 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ServiceSkeleton
|
2
4
|
class Error < StandardError
|
3
|
-
class InvalidEnvironmentError < Error; end
|
4
5
|
class CannotSanitizeEnvironmentError < Error; end
|
5
|
-
class
|
6
|
+
class InvalidEnvironmentError < Error; end
|
6
7
|
class InvalidMetricNameError < Error; end
|
8
|
+
class InvalidServiceClassError < Error; end
|
7
9
|
end
|
8
10
|
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "config"
|
4
|
+
require_relative "signal_manager"
|
5
|
+
require_relative "ultravisor_loggerstash"
|
6
|
+
|
7
|
+
require "frankenstein/ruby_gc_metrics"
|
8
|
+
require "frankenstein/ruby_vm_metrics"
|
9
|
+
require "frankenstein/process_metrics"
|
10
|
+
require "frankenstein/server"
|
11
|
+
require "prometheus/client/registry"
|
12
|
+
require "sigdump"
|
13
|
+
require "ultravisor"
|
14
|
+
|
15
|
+
module ServiceSkeleton
|
16
|
+
module Generator
|
17
|
+
def generate(config:, metrics_registry:, service_metrics:, service_signal_handlers:)
|
18
|
+
Ultravisor.new(logger: config.logger).tap do |ultravisor|
|
19
|
+
initialize_metrics(ultravisor, config, metrics_registry, service_metrics)
|
20
|
+
initialize_loggerstash(ultravisor, config, metrics_registry)
|
21
|
+
initialize_signals(ultravisor, config, service_signal_handlers, metrics_registry)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def initialize_metrics(ultravisor, config, registry, metrics)
|
28
|
+
Frankenstein::RubyGCMetrics.register(registry)
|
29
|
+
Frankenstein::RubyVMMetrics.register(registry)
|
30
|
+
Frankenstein::ProcessMetrics.register(registry)
|
31
|
+
|
32
|
+
metrics.each do |m|
|
33
|
+
registry.register(m)
|
34
|
+
|
35
|
+
method_name = m.method_name(config.service_name)
|
36
|
+
|
37
|
+
if registry.singleton_class.method_defined?(method_name)
|
38
|
+
raise ServiceSkeleton::Error::InvalidMetricNameError,
|
39
|
+
"Metric method #{method_name} is already defined"
|
40
|
+
end
|
41
|
+
|
42
|
+
registry.define_singleton_method(method_name) do
|
43
|
+
m
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if config.metrics_port
|
48
|
+
config.logger.info(config.service_name) { "Starting metrics server on port #{config.metrics_port}" }
|
49
|
+
ultravisor.add_child(
|
50
|
+
id: :metrics_server,
|
51
|
+
klass: Frankenstein::Server,
|
52
|
+
method: :run,
|
53
|
+
args: [
|
54
|
+
port: config.metrics_port,
|
55
|
+
logger: config.logger,
|
56
|
+
metrics_prefix: :"#{config.service_name}_metrics_server",
|
57
|
+
registry: registry,
|
58
|
+
]
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def initialize_loggerstash(ultravisor, config, registry)
|
64
|
+
if config.logstash_server && !config.logstash_server.empty?
|
65
|
+
config.logger.info(config.service_name) { "Configuring loggerstash to send to #{config.logstash_server}" }
|
66
|
+
|
67
|
+
ultravisor.add_child(
|
68
|
+
id: :logstash_writer,
|
69
|
+
klass: LogstashWriter,
|
70
|
+
method: :run,
|
71
|
+
args: [
|
72
|
+
server_name: config.logstash_server,
|
73
|
+
metrics_registry: registry,
|
74
|
+
logger: config.logger,
|
75
|
+
],
|
76
|
+
access: :unsafe
|
77
|
+
)
|
78
|
+
|
79
|
+
config.logger.singleton_class.prepend(Loggerstash::Mixin)
|
80
|
+
|
81
|
+
config.logger.instance_variable_set(:@ultravisor, ultravisor)
|
82
|
+
config.logger.singleton_class.prepend(ServiceSkeleton::UltravisorLoggerstash)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def initialize_signals(ultravisor, config, service_signals, metrics_registry)
|
87
|
+
counter = metrics_registry.counter(:"#{config.service_name}_signals_handled_total", docstring: "How many of each signal have been handled", labels: %i{signal})
|
88
|
+
|
89
|
+
ultravisor.add_child(
|
90
|
+
id: :signal_manager,
|
91
|
+
klass: ServiceSkeleton::SignalManager,
|
92
|
+
method: :run,
|
93
|
+
args: [
|
94
|
+
logger: config.logger,
|
95
|
+
counter: counter,
|
96
|
+
signals: global_signals(ultravisor, config.logger) + wrap_service_signals(service_signals, ultravisor),
|
97
|
+
],
|
98
|
+
shutdown: {
|
99
|
+
method: :shutdown,
|
100
|
+
timeout: 1,
|
101
|
+
}
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
def global_signals(ultravisor, logger)
|
106
|
+
# For mysterious reasons of mystery, simplecov doesn't recognise these
|
107
|
+
# procs as being called, even though there are definitely tests for
|
108
|
+
# them. So...
|
109
|
+
#:nocov:
|
110
|
+
[
|
111
|
+
[
|
112
|
+
"USR1",
|
113
|
+
->() {
|
114
|
+
logger.level -= 1 unless logger.level == Logger::DEBUG
|
115
|
+
logger.info($0) { "Received SIGUSR1; log level is now #{Logger::SEV_LABEL[logger.level]}." }
|
116
|
+
}
|
117
|
+
],
|
118
|
+
[
|
119
|
+
"USR2",
|
120
|
+
->() {
|
121
|
+
logger.level += 1 unless logger.level == Logger::ERROR
|
122
|
+
logger.info($0) { "Received SIGUSR2; log level is now #{Logger::SEV_LABEL[logger.level]}." }
|
123
|
+
}
|
124
|
+
],
|
125
|
+
[
|
126
|
+
"HUP",
|
127
|
+
->() {
|
128
|
+
logger.reopen
|
129
|
+
logger.info($0) { "Received SIGHUP; log file handle reopened" }
|
130
|
+
}
|
131
|
+
],
|
132
|
+
[
|
133
|
+
"QUIT",
|
134
|
+
->() { Sigdump.dump("+") }
|
135
|
+
],
|
136
|
+
[
|
137
|
+
"INT",
|
138
|
+
->() {
|
139
|
+
ultravisor.shutdown(wait: false, force: !!@shutting_down)
|
140
|
+
@shutting_down = true
|
141
|
+
}
|
142
|
+
],
|
143
|
+
[
|
144
|
+
"TERM",
|
145
|
+
->() {
|
146
|
+
ultravisor.shutdown(wait: false, force: !!@shutting_down)
|
147
|
+
@shutting_down = true
|
148
|
+
}
|
149
|
+
]
|
150
|
+
]
|
151
|
+
#:nocov:
|
152
|
+
end
|
153
|
+
|
154
|
+
def wrap_service_signals(signals, ultravisor)
|
155
|
+
[].tap do |signal_list|
|
156
|
+
signals.each do |service_name, sigs|
|
157
|
+
sigs.each do |sig, proc|
|
158
|
+
wrapped_proc = ->() { ultravisor[service_name.to_sym].unsafe_instance.instance_eval(&proc) }
|
159
|
+
signal_list << [sig, wrapped_proc]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|