service_skeleton 1.0.5 → 2.1.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +6 -2
- data/README.md +2 -54
- data/lib/service_skeleton/generator.rb +1 -1
- data/lib/service_skeleton/hurriable_timer.rb +61 -0
- data/lib/service_skeleton/hurriable_timer_sequence.rb +35 -0
- data/lib/service_skeleton/signal_manager.rb +1 -1
- data/lib/service_skeleton.rb +2 -0
- data/service_skeleton.gemspec +4 -12
- data/ultravisor/lib/ultravisor/child.rb +4 -0
- data/ultravisor/spec/spec_helper.rb +4 -2
- data/ultravisor/spec/ultravisor/child/spawn_spec.rb +112 -3
- metadata +14 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2eb043ee79208c4b1b457b1b9deb2b5901119339c9789d8a6d511870bc038e46
|
4
|
+
data.tar.gz: 6848edcb6fe369e5a6ce0dcf823780ee8047f8953b40ea261e03aa0f47314d27
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 43fe6a4e0ad9adb50cd78c09c41063df614a0116c194283710660b24f2877994038bb818e35ad78eb7b72da62c3ec7e75646fc2bfae5c6f85ef5fdd7a5289dba
|
7
|
+
data.tar.gz: 9aacd383f2d867a51b19adc8c1d501ad383497d13a72de0b8fa9992301b029cd23e60aaa3c72511e98f240ed060dd1dab6b8b38a89a9de3cce19a40c8c696f39
|
data/.github/workflows/ci.yml
CHANGED
@@ -4,7 +4,8 @@ on:
|
|
4
4
|
pull_request:
|
5
5
|
push:
|
6
6
|
branches:
|
7
|
-
-
|
7
|
+
- master
|
8
|
+
- main
|
8
9
|
|
9
10
|
jobs:
|
10
11
|
build:
|
@@ -14,6 +15,9 @@ jobs:
|
|
14
15
|
matrix:
|
15
16
|
ruby:
|
16
17
|
- 2.5
|
18
|
+
- 2.6
|
19
|
+
- 2.7
|
20
|
+
- 3.0
|
17
21
|
|
18
22
|
steps:
|
19
23
|
- uses: actions/checkout@v2
|
@@ -31,7 +35,7 @@ jobs:
|
|
31
35
|
run: bundle exec rake test
|
32
36
|
|
33
37
|
publish:
|
34
|
-
if: github.event_name == 'push' && (github.ref == 'refs/heads/
|
38
|
+
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master')
|
35
39
|
needs: build
|
36
40
|
runs-on: ubuntu-latest
|
37
41
|
|
data/README.md
CHANGED
@@ -268,7 +268,7 @@ default for a config variable, like so:
|
|
268
268
|
class GenericHelloService
|
269
269
|
include ServiceSkeleton
|
270
270
|
|
271
|
-
string :RECIPIENT, match: /\
|
271
|
+
string :RECIPIENT, match: /\A\w+\z/, default: "Anonymous Coward"
|
272
272
|
|
273
273
|
# ...
|
274
274
|
|
@@ -448,8 +448,7 @@ portion is the all-uppercase [service name](#the-service-name).
|
|
448
448
|
|
449
449
|
INFO,buggy=DEBUG,/noisy/i=ERROR
|
450
450
|
|
451
|
-
Logging levels can be changed at runtime
|
452
|
-
[the HTTP admin interface](#http-admin-interface).
|
451
|
+
Logging levels can be changed at runtime via [signals](#default-signals).
|
453
452
|
|
454
453
|
* **`<SERVICENAME>_LOGSTASH_SERVER`** (string; default `""`) -- if set to a
|
455
454
|
non-empty string, we will engage the services of the [loggerstash
|
@@ -686,57 +685,6 @@ When the service is shutdown, all signal handlers will be automatically
|
|
686
685
|
unhooked, which saves you having to do it yourself.
|
687
686
|
|
688
687
|
|
689
|
-
## HTTP Admin Interface
|
690
|
-
|
691
|
-
In these modern times we live in, it seems everything from nuclear reactors to
|
692
|
-
toasters can be controlled from a browser. Why should your services be any
|
693
|
-
different?
|
694
|
-
|
695
|
-
|
696
|
-
### HTTP Admin Configuration
|
697
|
-
|
698
|
-
In the spirit of "secure by default", you must explicitly enable the HTTP admin
|
699
|
-
interface, and configure an authentication method. To do that, use the
|
700
|
-
following environment variables, where `<SERVICENAME>_` is the all-uppercase
|
701
|
-
version of [the service name](#the-service-name).
|
702
|
-
|
703
|
-
* **`<SERVICENAME>_HTTP_ADMIN_PORT`** (integer; range 1..65535; default: `""`)
|
704
|
-
-- if set to a valid port number (`1` to `65535` inclusive), the HTTP admin
|
705
|
-
interface will listen on that port, if also enabled by configuring
|
706
|
-
authentication.
|
707
|
-
|
708
|
-
* **`<SERVICENAME>_HTTP_ADMIN_BASIC_AUTH`** (string; default: `""`) -- if set
|
709
|
-
to a string containing a username and password separated by a colon, then
|
710
|
-
authentication via [HTTP Basic auth](https://tools.ietf.org/html/rfc7617)
|
711
|
-
will be supported. Note that in addition to this setting, an admin port must
|
712
|
-
also be specified in order for the admin interface to be enabled.
|
713
|
-
|
714
|
-
* **`<SERVICENAME>_HTTP_ADMIN_PROXY_USERNAME_HEADER`** (string; default: `""`)
|
715
|
-
-- if set to a non-empty string, then incoming requests will be examined for
|
716
|
-
a HTTP header with the specified name. If such a header exists and has a
|
717
|
-
non-empty value, then the request will be deemed to have been authenticated
|
718
|
-
by an upstream authenticating proxy (such as
|
719
|
-
[`discourse-auth-proxy`](https://github.com/discourse/discourse-auth-proxy))
|
720
|
-
as the user given in the header value. Note that in addition to this
|
721
|
-
setting, an admin port must also be specified in order for the admin
|
722
|
-
interface to be enabled.
|
723
|
-
|
724
|
-
|
725
|
-
### HTTP Admin Usage
|
726
|
-
|
727
|
-
The HTTP admin interface provides both an interactive, browser-based mode,
|
728
|
-
as well as a RESTful interface, which should, in general, provide equivalent
|
729
|
-
functionality.
|
730
|
-
|
731
|
-
* Visiting the service's `IP address:port` in a web browser will bring up an HTML
|
732
|
-
interface showing all the features that are available. Usage should
|
733
|
-
(hopefully) be self-explanatory.
|
734
|
-
|
735
|
-
* Visiting the service's `IP address:port` whilst accepting `application/json`
|
736
|
-
responses will provide a directory of links to available endpoints which you
|
737
|
-
can use to interact with the HTTP admin interface programmatically.
|
738
|
-
|
739
|
-
|
740
688
|
# Contributing
|
741
689
|
|
742
690
|
Patches can be sent as [a Github pull
|
@@ -16,8 +16,8 @@ module ServiceSkeleton
|
|
16
16
|
module Generator
|
17
17
|
def generate(config:, metrics_registry:, service_metrics:, service_signal_handlers:)
|
18
18
|
Ultravisor.new(logger: config.logger).tap do |ultravisor|
|
19
|
-
initialize_metrics(ultravisor, config, metrics_registry, service_metrics)
|
20
19
|
initialize_loggerstash(ultravisor, config, metrics_registry)
|
20
|
+
initialize_metrics(ultravisor, config, metrics_registry, service_metrics)
|
21
21
|
initialize_signals(ultravisor, config, service_signal_handlers, metrics_registry)
|
22
22
|
end
|
23
23
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# A mechanism for waiting until a timer expires or until another thread signals
|
4
|
+
# readiness.
|
5
|
+
class ServiceSkeleton::HurriableTimer
|
6
|
+
def initialize(timeout)
|
7
|
+
@mutex = Mutex.new
|
8
|
+
@condition = ConditionVariable.new
|
9
|
+
@end_time = now + timeout
|
10
|
+
@hurried = false
|
11
|
+
end
|
12
|
+
|
13
|
+
# Wait for the timer to elapse
|
14
|
+
#
|
15
|
+
# Any number of threads can wait on the same HurriableTimer
|
16
|
+
def wait(t = nil)
|
17
|
+
end_time =
|
18
|
+
if t
|
19
|
+
[@end_time, now + t].min
|
20
|
+
else
|
21
|
+
@end_time
|
22
|
+
end
|
23
|
+
|
24
|
+
@mutex.synchronize {
|
25
|
+
while true
|
26
|
+
remaining = end_time - now
|
27
|
+
|
28
|
+
if remaining < 0 || @hurried
|
29
|
+
break
|
30
|
+
else
|
31
|
+
@condition.wait(@mutex, remaining)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
}
|
35
|
+
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# Cause the timer to trigger early if it hasn't already expired
|
40
|
+
#
|
41
|
+
# This method is idempotent
|
42
|
+
def hurry!
|
43
|
+
@mutex.synchronize {
|
44
|
+
@hurried = true
|
45
|
+
@condition.broadcast
|
46
|
+
}
|
47
|
+
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def expired?
|
52
|
+
@hurried || @end_time - now < 0
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def now
|
58
|
+
# Using this instead of Time.now, because it isn't affected by NTP updates
|
59
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW)
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# HurribleTimerSequence is a resettable version of HurriableTimer, designed for
|
4
|
+
# cases where some action needs to happen at at least some frequency, but may
|
5
|
+
# happen more often when other threads trigger the process early.
|
6
|
+
#
|
7
|
+
# It would have been possible to implement this without requiring allocation on
|
8
|
+
# reset, by reusing the mutex and condition variable in the normal timer, but
|
9
|
+
# this version is more obviously correct.
|
10
|
+
class ServiceSkeleton::HurriableTimerSequence
|
11
|
+
def initialize(timeout)
|
12
|
+
@mutex = Mutex.new
|
13
|
+
@timeout = timeout
|
14
|
+
@latest = ServiceSkeleton::HurriableTimer.new(@timeout)
|
15
|
+
end
|
16
|
+
|
17
|
+
def reset!
|
18
|
+
@mutex.synchronize {
|
19
|
+
@latest.hurry!
|
20
|
+
@latest = ServiceSkeleton::HurriableTimer.new(@timeout)
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def wait(t = nil)
|
25
|
+
@mutex.synchronize { @latest }.wait(t)
|
26
|
+
end
|
27
|
+
|
28
|
+
def hurry!
|
29
|
+
@mutex.synchronize { @latest }.hurry!
|
30
|
+
end
|
31
|
+
|
32
|
+
def expired?
|
33
|
+
@mutex.synchronize { @latest }.expired?
|
34
|
+
end
|
35
|
+
end
|
data/lib/service_skeleton.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
require_relative "service_skeleton/config_class"
|
4
4
|
require_relative "service_skeleton/config_variables"
|
5
5
|
require_relative "service_skeleton/generator"
|
6
|
+
require_relative "service_skeleton/hurriable_timer"
|
7
|
+
require_relative "service_skeleton/hurriable_timer_sequence"
|
6
8
|
require_relative "service_skeleton/logging_helpers"
|
7
9
|
require_relative "service_skeleton/metrics_methods"
|
8
10
|
require_relative "service_skeleton/service_name"
|
data/service_skeleton.gemspec
CHANGED
@@ -1,15 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
begin
|
4
|
-
require 'git-version-bump'
|
5
|
-
rescue LoadError
|
6
|
-
nil
|
7
|
-
end
|
8
|
-
|
9
3
|
Gem::Specification.new do |s|
|
10
4
|
s.name = "service_skeleton"
|
11
5
|
|
12
|
-
s.version = '1.0
|
6
|
+
s.version = '2.1.0'
|
13
7
|
|
14
8
|
s.platform = Gem::Platform::RUBY
|
15
9
|
|
@@ -32,22 +26,20 @@ Gem::Specification.new do |s|
|
|
32
26
|
s.required_ruby_version = ">= 2.5.0"
|
33
27
|
|
34
28
|
s.add_runtime_dependency "frankenstein", "~> 2.0"
|
35
|
-
s.add_runtime_dependency "loggerstash", "
|
29
|
+
s.add_runtime_dependency "loggerstash", "~> 1"
|
36
30
|
s.add_runtime_dependency "prometheus-client", "~> 2.0"
|
37
31
|
s.add_runtime_dependency "sigdump", "~> 0.2"
|
38
32
|
s.add_runtime_dependency "to_regexp", "~> 0.2"
|
33
|
+
s.add_runtime_dependency "webrick"
|
39
34
|
|
40
35
|
s.add_development_dependency 'bundler'
|
41
|
-
s.add_development_dependency 'github-release'
|
42
|
-
s.add_development_dependency 'git-version-bump'
|
43
36
|
s.add_development_dependency 'guard-rspec'
|
44
37
|
s.add_development_dependency 'guard-rubocop'
|
45
38
|
s.add_development_dependency 'rack-test'
|
46
39
|
s.add_development_dependency 'rake'
|
47
40
|
s.add_development_dependency 'redcarpet'
|
48
41
|
s.add_development_dependency 'rspec'
|
49
|
-
s.add_development_dependency 'rubocop'
|
50
|
-
s.add_development_dependency 'rubocop-discourse'
|
42
|
+
s.add_development_dependency 'rubocop-discourse', '~> 2.4.1'
|
51
43
|
s.add_development_dependency 'simplecov'
|
52
44
|
s.add_development_dependency 'yard'
|
53
45
|
end
|
@@ -381,6 +381,10 @@ class Ultravisor
|
|
381
381
|
# urgh.
|
382
382
|
if @klass.instance_method(:initialize).arity == 0
|
383
383
|
@klass.new()
|
384
|
+
elsif @args.is_a?(Hash)
|
385
|
+
@klass.new(**@args)
|
386
|
+
elsif @args.last.is_a?(Hash)
|
387
|
+
@klass.new(*@args[0...-1], **@args.last)
|
384
388
|
else
|
385
389
|
@klass.new(*@args)
|
386
390
|
end.tap do |i|
|
@@ -93,14 +93,123 @@ describe Ultravisor::Child do
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
-
context "with a worker class that takes args" do
|
96
|
+
context "with a worker class that takes only non-keyword args" do
|
97
|
+
let(:args) { { id: :testy, klass: mock_class, args: ["foo", "bar"], method: :run } }
|
98
|
+
let(:mock_class) do
|
99
|
+
Class.new do
|
100
|
+
def initialize(foo, bar)
|
101
|
+
end
|
102
|
+
|
103
|
+
def run
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
it "creates the class instance with args" do
|
109
|
+
allow(mock_class).to receive(:new).and_call_original
|
110
|
+
|
111
|
+
child.spawn(term_queue).wait
|
112
|
+
expect(mock_class).to have_received(:new).with("foo", "bar")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "with a worker class that takes non-keyword and optional args" do
|
97
117
|
let(:args) { { id: :testy, klass: mock_class, args: ["foo", "bar", baz: "wombat"], method: :run } }
|
98
|
-
let(:mock_class)
|
118
|
+
let(:mock_class) do
|
119
|
+
Class.new do
|
120
|
+
def initialize(foo, bar, baz = {})
|
121
|
+
end
|
122
|
+
|
123
|
+
def run
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
99
127
|
|
100
128
|
it "creates the class instance with args" do
|
101
|
-
|
129
|
+
allow(mock_class).to receive(:new).and_call_original
|
102
130
|
|
103
131
|
child.spawn(term_queue).wait
|
132
|
+
expect(mock_class).to have_received(:new).with("foo", "bar", { baz: "wombat" })
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context "with a worker class that takes mixed args" do
|
137
|
+
let(:args) { { id: :testy, klass: mock_class, args: ["foo", "bar", baz: "wombat"], method: :run } }
|
138
|
+
let(:mock_class) do
|
139
|
+
Class.new do
|
140
|
+
def initialize(foo, bar, baz:)
|
141
|
+
end
|
142
|
+
|
143
|
+
def run
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
it "creates the class instance with args" do
|
149
|
+
allow(mock_class).to receive(:new).and_call_original
|
150
|
+
|
151
|
+
child.spawn(term_queue).wait
|
152
|
+
expect(mock_class).to have_received(:new).with("foo", "bar", baz: "wombat")
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context "with a worker class that takes keyword args" do
|
157
|
+
let(:args) { { id: :testy, klass: mock_class, args: [foo: "bar", baz: "wombat"], method: :run } }
|
158
|
+
let(:mock_class) do
|
159
|
+
Class.new do
|
160
|
+
def initialize(foo:, baz:)
|
161
|
+
end
|
162
|
+
|
163
|
+
def run
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
it "creates the class instance with args" do
|
169
|
+
allow(mock_class).to receive(:new).and_call_original
|
170
|
+
|
171
|
+
child.spawn(term_queue).wait
|
172
|
+
expect(mock_class).to have_received(:new).with(foo: "bar", baz: "wombat")
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context "with a worker class that takes optional args" do
|
177
|
+
let(:args) { { id: :testy, klass: mock_class, args: [foo: "bar", baz: "wombat", fib: "wib", woop: "woob"], method: :run } }
|
178
|
+
let(:mock_class) do
|
179
|
+
Class.new do
|
180
|
+
def initialize(foo:, baz:, fib: "none", woop: nil)
|
181
|
+
end
|
182
|
+
|
183
|
+
def run
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
it "creates the class instance with args" do
|
189
|
+
allow(mock_class).to receive(:new).and_call_original
|
190
|
+
child.spawn(term_queue).wait
|
191
|
+
|
192
|
+
expect(mock_class).to have_received(:new).with(foo: "bar", baz: "wombat", fib: "wib", woop: "woob")
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
context "with a worker class that takes keyword args in form of a hash" do
|
197
|
+
let(:args) { { id: :testy, klass: mock_class, args: { foo: "bar", baz: "wombat" }, method: :run } }
|
198
|
+
let(:mock_class) do
|
199
|
+
Class.new do
|
200
|
+
def initialize(foo:, baz:)
|
201
|
+
end
|
202
|
+
|
203
|
+
def run
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
it "creates the class instance with args" do
|
209
|
+
allow(mock_class).to receive(:new).and_call_original
|
210
|
+
child.spawn(term_queue).wait
|
211
|
+
|
212
|
+
expect(mock_class).to have_received(:new).with(foo: "bar", baz: "wombat")
|
104
213
|
end
|
105
214
|
end
|
106
215
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: service_skeleton
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Palmer
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-01-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: frankenstein
|
@@ -29,20 +29,14 @@ dependencies:
|
|
29
29
|
name: loggerstash
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - "
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version: 0.0.9
|
35
|
-
- - "<"
|
32
|
+
- - "~>"
|
36
33
|
- !ruby/object:Gem::Version
|
37
34
|
version: '1'
|
38
35
|
type: :runtime
|
39
36
|
prerelease: false
|
40
37
|
version_requirements: !ruby/object:Gem::Requirement
|
41
38
|
requirements:
|
42
|
-
- - "
|
43
|
-
- !ruby/object:Gem::Version
|
44
|
-
version: 0.0.9
|
45
|
-
- - "<"
|
39
|
+
- - "~>"
|
46
40
|
- !ruby/object:Gem::Version
|
47
41
|
version: '1'
|
48
42
|
- !ruby/object:Gem::Dependency
|
@@ -88,27 +82,13 @@ dependencies:
|
|
88
82
|
- !ruby/object:Gem::Version
|
89
83
|
version: '0.2'
|
90
84
|
- !ruby/object:Gem::Dependency
|
91
|
-
name:
|
85
|
+
name: webrick
|
92
86
|
requirement: !ruby/object:Gem::Requirement
|
93
87
|
requirements:
|
94
88
|
- - ">="
|
95
89
|
- !ruby/object:Gem::Version
|
96
90
|
version: '0'
|
97
|
-
type: :
|
98
|
-
prerelease: false
|
99
|
-
version_requirements: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
- !ruby/object:Gem::Dependency
|
105
|
-
name: github-release
|
106
|
-
requirement: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
|
-
type: :development
|
91
|
+
type: :runtime
|
112
92
|
prerelease: false
|
113
93
|
version_requirements: !ruby/object:Gem::Requirement
|
114
94
|
requirements:
|
@@ -116,7 +96,7 @@ dependencies:
|
|
116
96
|
- !ruby/object:Gem::Version
|
117
97
|
version: '0'
|
118
98
|
- !ruby/object:Gem::Dependency
|
119
|
-
name:
|
99
|
+
name: bundler
|
120
100
|
requirement: !ruby/object:Gem::Requirement
|
121
101
|
requirements:
|
122
102
|
- - ">="
|
@@ -213,34 +193,20 @@ dependencies:
|
|
213
193
|
- - ">="
|
214
194
|
- !ruby/object:Gem::Version
|
215
195
|
version: '0'
|
216
|
-
- !ruby/object:Gem::Dependency
|
217
|
-
name: rubocop
|
218
|
-
requirement: !ruby/object:Gem::Requirement
|
219
|
-
requirements:
|
220
|
-
- - ">="
|
221
|
-
- !ruby/object:Gem::Version
|
222
|
-
version: '0'
|
223
|
-
type: :development
|
224
|
-
prerelease: false
|
225
|
-
version_requirements: !ruby/object:Gem::Requirement
|
226
|
-
requirements:
|
227
|
-
- - ">="
|
228
|
-
- !ruby/object:Gem::Version
|
229
|
-
version: '0'
|
230
196
|
- !ruby/object:Gem::Dependency
|
231
197
|
name: rubocop-discourse
|
232
198
|
requirement: !ruby/object:Gem::Requirement
|
233
199
|
requirements:
|
234
|
-
- - "
|
200
|
+
- - "~>"
|
235
201
|
- !ruby/object:Gem::Version
|
236
|
-
version:
|
202
|
+
version: 2.4.1
|
237
203
|
type: :development
|
238
204
|
prerelease: false
|
239
205
|
version_requirements: !ruby/object:Gem::Requirement
|
240
206
|
requirements:
|
241
|
-
- - "
|
207
|
+
- - "~>"
|
242
208
|
- !ruby/object:Gem::Version
|
243
|
-
version:
|
209
|
+
version: 2.4.1
|
244
210
|
- !ruby/object:Gem::Dependency
|
245
211
|
name: simplecov
|
246
212
|
requirement: !ruby/object:Gem::Requirement
|
@@ -309,6 +275,8 @@ files:
|
|
309
275
|
- lib/service_skeleton/error.rb
|
310
276
|
- lib/service_skeleton/filtering_logger.rb
|
311
277
|
- lib/service_skeleton/generator.rb
|
278
|
+
- lib/service_skeleton/hurriable_timer.rb
|
279
|
+
- lib/service_skeleton/hurriable_timer_sequence.rb
|
312
280
|
- lib/service_skeleton/logging_helpers.rb
|
313
281
|
- lib/service_skeleton/metric_method_name.rb
|
314
282
|
- lib/service_skeleton/metrics_methods.rb
|
@@ -368,7 +336,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
368
336
|
- !ruby/object:Gem::Version
|
369
337
|
version: '0'
|
370
338
|
requirements: []
|
371
|
-
rubygems_version: 3.1.
|
339
|
+
rubygems_version: 3.1.6
|
372
340
|
signing_key:
|
373
341
|
specification_version: 4
|
374
342
|
summary: The bare bones of a service
|