service_skeleton 2.0.2 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
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: []