service_skeleton 1.0.5 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|