service_skeleton 2.0.2 → 2.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7d49a02ddaf68cb61da78352ed7f114f1ba12034dcd02852ce20aab2c87ea390
4
- data.tar.gz: 9090f37cac4cc61fa538fc56a34c859fd44adc252e0fd212ea3a63a877a46666
3
+ metadata.gz: f06ab46da1ee2c8366933e34efe02686cfca1758cff0667fb05b6ef5a42e9db6
4
+ data.tar.gz: 17cc7ba27c8cd63f6e74831e69da68c860803af15e77eb6f4a52686754107138
5
5
  SHA512:
6
- metadata.gz: 85685190eb12f5072744e7098f529cf12fc4755483fee50a47f8f46db7b83acf587eed549e973a02d903dd4a5d9bf9929c24a515996002e6b072629ff780af9d
7
- data.tar.gz: e80d673512846c362094c962b21ffdababeae718194d9ba48b60dc73f733b8ccc820fbff8c1766f1a48eb4ccc2deb912fb6194bd788d526d7241bfd10b9d9295
6
+ metadata.gz: c3137b6133e59bd2c9aa990bd85216b6acdf09a1d6174ae0fa06a1c2ff55e898f266f131a69457dd39f363fcdef35d67d0f9fd1e9255f6a8e9b4ebdd2f4a5ed9
7
+ data.tar.gz: dbba001733bcf0717673335d1ff52d6eb33b0a88b602c7f3be2d378addb37c0da585fba5c15d6ddff106f0dd69663935d541583ea521376b8136711eef53f3b8
@@ -4,23 +4,41 @@ on:
4
4
  pull_request:
5
5
  push:
6
6
  branches:
7
- - master
8
7
  - main
9
8
 
10
9
  jobs:
10
+ lint:
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - name: Setup ruby
17
+ uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: "3.2"
20
+ bundler-cache: true
21
+
22
+ - name: Lint
23
+ run: bundle exec rubocop
24
+
11
25
  build:
12
26
  runs-on: ubuntu-latest
13
27
 
14
28
  strategy:
29
+ fail-fast: false
30
+
15
31
  matrix:
16
32
  ruby:
17
- - 2.5
18
- - 2.6
19
- - 2.7
20
- - 3.0
33
+ - "2.5"
34
+ - "2.6"
35
+ - "2.7"
36
+ - "3.0"
37
+ - "3.1"
38
+ - "3.2"
21
39
 
22
40
  steps:
23
- - uses: actions/checkout@v2
41
+ - uses: actions/checkout@v4
24
42
 
25
43
  - name: Setup ruby
26
44
  uses: ruby/setup-ruby@v1
@@ -28,22 +46,19 @@ jobs:
28
46
  ruby-version: ${{ matrix.ruby }}
29
47
  bundler-cache: true
30
48
 
31
- - name: Lint
32
- run: bundle exec rubocop
33
-
34
49
  - name: Tests
35
50
  run: bundle exec rake test
36
51
 
37
52
  publish:
38
- if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master')
39
- needs: build
53
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
54
+ needs: [lint, build]
40
55
  runs-on: ubuntu-latest
41
56
 
42
57
  steps:
43
- - uses: actions/checkout@v2
58
+ - uses: actions/checkout@v4
44
59
 
45
60
  - name: Release Gem
46
- uses: discourse/publish-rubygems-action@v2-beta
61
+ uses: discourse/publish-rubygems-action@v3
47
62
  env:
48
63
  RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
49
64
  GIT_EMAIL: team@discourse.org
data/.rubocop.yml CHANGED
@@ -8,4 +8,4 @@ inherit_mode:
8
8
  RSpec/MessageSpies:
9
9
  EnforcedStyle: receive
10
10
  Exclude:
11
- - "ultravisor/**/*"
11
+ - "ultravisor/**/*"
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: /\a\w+\z/, default: "Anonymous Coward"
271
+ string :RECIPIENT, match: /\A\w+\z/, default: "Anonymous Coward"
272
272
 
273
273
  # ...
274
274
 
@@ -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
@@ -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"
@@ -3,7 +3,7 @@
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "service_skeleton"
5
5
 
6
- s.version = '2.0.2'
6
+ s.version = '2.2.0'
7
7
 
8
8
  s.platform = Gem::Platform::RUBY
9
9
 
@@ -39,7 +39,7 @@ Gem::Specification.new do |s|
39
39
  s.add_development_dependency 'rake'
40
40
  s.add_development_dependency 'redcarpet'
41
41
  s.add_development_dependency 'rspec'
42
- s.add_development_dependency 'rubocop-discourse', '~> 2.4.1'
42
+ s.add_development_dependency 'rubocop-discourse', '~> 3.4.1'
43
43
  s.add_development_dependency 'simplecov'
44
44
  s.add_development_dependency 'yard'
45
45
  end
@@ -11,4 +11,5 @@ class Ultravisor::Child::CallReceiver < BasicObject
11
11
  @blk.call(callback)
12
12
  rv_q.pop.tap { |rv| ::Kernel.raise ::Ultravisor::ChildRestartedError.new if rv == rv_fail }
13
13
  end
14
+ ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
14
15
  end
@@ -8,4 +8,5 @@ class Ultravisor::Child::CastReceiver < BasicObject
8
8
  castback = ::Ultravisor::Child::Cast.new(name, args, blk)
9
9
  @blk.call(castback)
10
10
  end
11
+ ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
11
12
  end
@@ -7,8 +7,10 @@ require 'rspec/mocks'
7
7
  Thread.report_on_exception = false
8
8
 
9
9
  require 'simplecov'
10
- SimpleCov.start do
11
- add_filter('spec')
10
+ unless SimpleCov.running
11
+ SimpleCov.start do
12
+ add_filter('spec')
13
+ end
12
14
  end
13
15
 
14
16
  class ListIncompletelyCoveredFiles
@@ -106,6 +106,30 @@ describe Ultravisor::Child do
106
106
 
107
107
  expect { child.cast.to_s }.to_not raise_error
108
108
  end
109
+
110
+ context "with keyword arguments" do
111
+ class Child
112
+ def run
113
+ end
114
+
115
+ def process
116
+ process_castcall
117
+ end
118
+
119
+ def kwarg(message:)
120
+ raise "#{message} was passed"
121
+ end
122
+ end
123
+
124
+ let(:args) do
125
+ { id: :child, klass: Child, method: :run, enable_castcall: true, access: :unsafe }
126
+ end
127
+
128
+ it "forwards them" do
129
+ child.cast.kwarg(message: "hey")
130
+ expect { child.unsafe_instance.process }.to raise_error("hey was passed")
131
+ end
132
+ end
109
133
  end
110
134
  end
111
135
  end
@@ -10,7 +10,7 @@ describe Ultravisor::Child do
10
10
  let(:mock_class) { Class.new.tap { |k| k.class_eval { def run; end } } }
11
11
 
12
12
  describe "#restart_delay" do
13
- context "by default" do
13
+ context "with default args" do
14
14
  let(:args) { base_args }
15
15
 
16
16
  it "returns the default delay" do
@@ -77,7 +77,7 @@ describe Ultravisor::Child do
77
77
  expect(@thread).to have_received(:join).with(0.05)
78
78
  end
79
79
 
80
- context "the worker doesn't finish quickly enough" do
80
+ context "when the worker doesn't finish quickly enough" do
81
81
  before(:each) do
82
82
  allow(mock_instance).to receive(:run) { sleep 15 }
83
83
  end
@@ -10,7 +10,7 @@ describe Ultravisor::Child do
10
10
  let(:child) { Ultravisor::Child.new(**args) }
11
11
 
12
12
  describe "#unsafe_instance" do
13
- context "by default" do
13
+ context "with default args" do
14
14
  it "explodes" do
15
15
  expect { child.unsafe_instance }.to raise_error(Ultravisor::ThreadSafetyError)
16
16
  end
@@ -69,13 +69,13 @@ describe Ultravisor do
69
69
  ultravisor.run
70
70
  end
71
71
 
72
- context "that terminates" do
72
+ context "when the child terminates" do
73
73
  before(:each) do
74
74
  allow(ultravisor.instance_variable_get(:@queue)).to receive(:pop).and_return(child, :shutdown)
75
75
  allow(ultravisor).to receive(:sleep)
76
76
  end
77
77
 
78
- context "within the limits of its restart policy" do
78
+ context "when in the limits of its restart policy" do
79
79
  it "spawns the child again" do
80
80
  expect(child).to receive(:spawn).exactly(:twice)
81
81
 
@@ -89,7 +89,7 @@ describe Ultravisor do
89
89
  end
90
90
  end
91
91
 
92
- context "too often for its restart policy" do
92
+ context "when it terminates too often for its restart policy" do
93
93
  before(:each) do
94
94
  allow(child).to receive(:restart?).and_raise(Ultravisor::BlownRestartPolicyError)
95
95
  allow(logger).to receive(:error)
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: service_skeleton
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Palmer
8
8
  - Sam Saffron
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-03-04 00:00:00.000000000 Z
12
+ date: 2023-12-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: frankenstein
@@ -199,14 +199,14 @@ dependencies:
199
199
  requirements:
200
200
  - - "~>"
201
201
  - !ruby/object:Gem::Version
202
- version: 2.4.1
202
+ version: 3.4.1
203
203
  type: :development
204
204
  prerelease: false
205
205
  version_requirements: !ruby/object:Gem::Requirement
206
206
  requirements:
207
207
  - - "~>"
208
208
  - !ruby/object:Gem::Version
209
- version: 2.4.1
209
+ version: 3.4.1
210
210
  - !ruby/object:Gem::Dependency
211
211
  name: simplecov
212
212
  requirement: !ruby/object:Gem::Requirement
@@ -275,6 +275,8 @@ files:
275
275
  - lib/service_skeleton/error.rb
276
276
  - lib/service_skeleton/filtering_logger.rb
277
277
  - lib/service_skeleton/generator.rb
278
+ - lib/service_skeleton/hurriable_timer.rb
279
+ - lib/service_skeleton/hurriable_timer_sequence.rb
278
280
  - lib/service_skeleton/logging_helpers.rb
279
281
  - lib/service_skeleton/metric_method_name.rb
280
282
  - lib/service_skeleton/metrics_methods.rb
@@ -319,7 +321,7 @@ files:
319
321
  homepage: https://github.com/discourse/service_skeleton
320
322
  licenses: []
321
323
  metadata: {}
322
- post_install_message:
324
+ post_install_message:
323
325
  rdoc_options: []
324
326
  require_paths:
325
327
  - lib
@@ -334,8 +336,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
334
336
  - !ruby/object:Gem::Version
335
337
  version: '0'
336
338
  requirements: []
337
- rubygems_version: 3.1.4
338
- signing_key:
339
+ rubygems_version: 3.4.10
340
+ signing_key:
339
341
  specification_version: 4
340
342
  summary: The bare bones of a service
341
343
  test_files: []