always 0.0.3 → 0.0.5
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/.rubocop.yml +5 -0
- data/Gemfile +3 -3
- data/Gemfile.lock +36 -45
- data/README.md +15 -3
- data/always.gemspec +1 -1
- data/lib/always.rb +37 -16
- data/test/test_always.rb +43 -6
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3e58e6ba3b68a86d0f9fc12a7bc34580085f00b4511e5ea34167465338a51789
|
|
4
|
+
data.tar.gz: cac5d0bc4f8d7d16aff1ae095e4b204c431737603fa2a3be4245c10a44d0bb84
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ec65e4cc308a110d2867ca647e197061b1811b15a09da8dd9e5e71259135808409c0e26d47c738d9e0c3187cf93050caec5779622cf9c5a8f14e895befaf18c9
|
|
7
|
+
data.tar.gz: 6fa3988429a11ef790c92715a23a9f31a4445ffd27fcbc5eaa8ecfd91d5d42f7c7da18d6ee18802d4f0000bd9c6b9ad86ee84a1a1e9e9c333e94a75633e48bd8
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
source 'https://rubygems.org'
|
|
24
24
|
gemspec
|
|
25
25
|
|
|
26
|
-
gem 'minitest', '5.
|
|
26
|
+
gem 'minitest', '5.24.1', require: false
|
|
27
27
|
gem 'rake', '13.2.1', require: false
|
|
28
|
-
gem 'rspec-rails', '6.1.
|
|
28
|
+
gem 'rspec-rails', '6.1.3', require: false
|
|
29
29
|
gem 'rubocop', '1.64.1', require: false
|
|
30
|
-
gem 'rubocop-rspec', '
|
|
30
|
+
gem 'rubocop-rspec', '3.0.2', require: false
|
|
31
31
|
gem 'simplecov', '0.22.0', require: false
|
|
32
32
|
gem 'simplecov-cobertura', '2.1.0', require: false
|
|
33
33
|
gem 'yard', '0.9.36', require: false
|
data/Gemfile.lock
CHANGED
|
@@ -7,9 +7,9 @@ PATH
|
|
|
7
7
|
GEM
|
|
8
8
|
remote: https://rubygems.org/
|
|
9
9
|
specs:
|
|
10
|
-
actionpack (7.1.3.
|
|
11
|
-
actionview (= 7.1.3.
|
|
12
|
-
activesupport (= 7.1.3.
|
|
10
|
+
actionpack (7.1.3.4)
|
|
11
|
+
actionview (= 7.1.3.4)
|
|
12
|
+
activesupport (= 7.1.3.4)
|
|
13
13
|
nokogiri (>= 1.8.5)
|
|
14
14
|
racc
|
|
15
15
|
rack (>= 2.2.4)
|
|
@@ -17,13 +17,13 @@ GEM
|
|
|
17
17
|
rack-test (>= 0.6.3)
|
|
18
18
|
rails-dom-testing (~> 2.2)
|
|
19
19
|
rails-html-sanitizer (~> 1.6)
|
|
20
|
-
actionview (7.1.3.
|
|
21
|
-
activesupport (= 7.1.3.
|
|
20
|
+
actionview (7.1.3.4)
|
|
21
|
+
activesupport (= 7.1.3.4)
|
|
22
22
|
builder (~> 3.1)
|
|
23
23
|
erubi (~> 1.11)
|
|
24
24
|
rails-dom-testing (~> 2.2)
|
|
25
25
|
rails-html-sanitizer (~> 1.6)
|
|
26
|
-
activesupport (7.1.3.
|
|
26
|
+
activesupport (7.1.3.4)
|
|
27
27
|
base64
|
|
28
28
|
bigdecimal
|
|
29
29
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
@@ -36,18 +36,18 @@ GEM
|
|
|
36
36
|
ast (2.4.2)
|
|
37
37
|
base64 (0.2.0)
|
|
38
38
|
bigdecimal (3.1.8)
|
|
39
|
-
builder (3.
|
|
40
|
-
concurrent-ruby (1.3.
|
|
39
|
+
builder (3.3.0)
|
|
40
|
+
concurrent-ruby (1.3.3)
|
|
41
41
|
connection_pool (2.4.1)
|
|
42
42
|
crass (1.0.6)
|
|
43
43
|
diff-lcs (1.5.1)
|
|
44
44
|
docile (1.4.0)
|
|
45
45
|
drb (2.2.1)
|
|
46
|
-
erubi (1.
|
|
46
|
+
erubi (1.13.0)
|
|
47
47
|
i18n (1.14.5)
|
|
48
48
|
concurrent-ruby (~> 1.0)
|
|
49
49
|
io-console (0.7.2)
|
|
50
|
-
irb (1.13.
|
|
50
|
+
irb (1.13.2)
|
|
51
51
|
rdoc (>= 4.0.0)
|
|
52
52
|
reline (>= 0.4.2)
|
|
53
53
|
json (2.7.2)
|
|
@@ -55,30 +55,30 @@ GEM
|
|
|
55
55
|
loofah (2.22.0)
|
|
56
56
|
crass (~> 1.0.2)
|
|
57
57
|
nokogiri (>= 1.12.0)
|
|
58
|
-
minitest (5.
|
|
58
|
+
minitest (5.24.1)
|
|
59
59
|
mutex_m (0.2.0)
|
|
60
|
-
nokogiri (1.16.
|
|
60
|
+
nokogiri (1.16.6-aarch64-linux)
|
|
61
61
|
racc (~> 1.4)
|
|
62
|
-
nokogiri (1.16.
|
|
62
|
+
nokogiri (1.16.6-arm-linux)
|
|
63
63
|
racc (~> 1.4)
|
|
64
|
-
nokogiri (1.16.
|
|
64
|
+
nokogiri (1.16.6-arm64-darwin)
|
|
65
65
|
racc (~> 1.4)
|
|
66
|
-
nokogiri (1.16.
|
|
66
|
+
nokogiri (1.16.6-x64-mingw-ucrt)
|
|
67
67
|
racc (~> 1.4)
|
|
68
|
-
nokogiri (1.16.
|
|
68
|
+
nokogiri (1.16.6-x86-linux)
|
|
69
69
|
racc (~> 1.4)
|
|
70
|
-
nokogiri (1.16.
|
|
70
|
+
nokogiri (1.16.6-x86_64-darwin)
|
|
71
71
|
racc (~> 1.4)
|
|
72
|
-
nokogiri (1.16.
|
|
72
|
+
nokogiri (1.16.6-x86_64-linux)
|
|
73
73
|
racc (~> 1.4)
|
|
74
|
-
parallel (1.
|
|
75
|
-
parser (3.3.
|
|
74
|
+
parallel (1.25.1)
|
|
75
|
+
parser (3.3.3.0)
|
|
76
76
|
ast (~> 2.4.1)
|
|
77
77
|
racc
|
|
78
78
|
psych (5.1.2)
|
|
79
79
|
stringio
|
|
80
80
|
racc (1.8.0)
|
|
81
|
-
rack (3.
|
|
81
|
+
rack (3.1.6)
|
|
82
82
|
rack-session (2.0.0)
|
|
83
83
|
rack (>= 3.0.0)
|
|
84
84
|
rack-test (2.1.0)
|
|
@@ -93,9 +93,9 @@ GEM
|
|
|
93
93
|
rails-html-sanitizer (1.6.0)
|
|
94
94
|
loofah (~> 2.21)
|
|
95
95
|
nokogiri (~> 1.14)
|
|
96
|
-
railties (7.1.3.
|
|
97
|
-
actionpack (= 7.1.3.
|
|
98
|
-
activesupport (= 7.1.3.
|
|
96
|
+
railties (7.1.3.4)
|
|
97
|
+
actionpack (= 7.1.3.4)
|
|
98
|
+
activesupport (= 7.1.3.4)
|
|
99
99
|
irb
|
|
100
100
|
rackup (>= 1.0.0)
|
|
101
101
|
rake (>= 12.2)
|
|
@@ -106,19 +106,19 @@ GEM
|
|
|
106
106
|
rdoc (6.7.0)
|
|
107
107
|
psych (>= 4.0.0)
|
|
108
108
|
regexp_parser (2.9.2)
|
|
109
|
-
reline (0.5.
|
|
109
|
+
reline (0.5.9)
|
|
110
110
|
io-console (~> 0.5)
|
|
111
|
-
rexml (3.
|
|
112
|
-
strscan
|
|
111
|
+
rexml (3.3.1)
|
|
112
|
+
strscan
|
|
113
113
|
rspec-core (3.13.0)
|
|
114
114
|
rspec-support (~> 3.13.0)
|
|
115
|
-
rspec-expectations (3.13.
|
|
115
|
+
rspec-expectations (3.13.1)
|
|
116
116
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
117
117
|
rspec-support (~> 3.13.0)
|
|
118
118
|
rspec-mocks (3.13.1)
|
|
119
119
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
120
120
|
rspec-support (~> 3.13.0)
|
|
121
|
-
rspec-rails (6.1.
|
|
121
|
+
rspec-rails (6.1.3)
|
|
122
122
|
actionpack (>= 6.1)
|
|
123
123
|
activesupport (>= 6.1)
|
|
124
124
|
railties (>= 6.1)
|
|
@@ -140,17 +140,8 @@ GEM
|
|
|
140
140
|
unicode-display_width (>= 2.4.0, < 3.0)
|
|
141
141
|
rubocop-ast (1.31.3)
|
|
142
142
|
parser (>= 3.3.1.0)
|
|
143
|
-
rubocop-
|
|
144
|
-
rubocop (~> 1.
|
|
145
|
-
rubocop-factory_bot (2.25.1)
|
|
146
|
-
rubocop (~> 1.41)
|
|
147
|
-
rubocop-rspec (2.29.2)
|
|
148
|
-
rubocop (~> 1.40)
|
|
149
|
-
rubocop-capybara (~> 2.17)
|
|
150
|
-
rubocop-factory_bot (~> 2.22)
|
|
151
|
-
rubocop-rspec_rails (~> 2.28)
|
|
152
|
-
rubocop-rspec_rails (2.28.3)
|
|
153
|
-
rubocop (~> 1.40)
|
|
143
|
+
rubocop-rspec (3.0.2)
|
|
144
|
+
rubocop (~> 1.61)
|
|
154
145
|
ruby-progressbar (1.13.0)
|
|
155
146
|
simplecov (0.22.0)
|
|
156
147
|
docile (~> 1.1)
|
|
@@ -161,7 +152,7 @@ GEM
|
|
|
161
152
|
simplecov (~> 0.19)
|
|
162
153
|
simplecov-html (0.12.3)
|
|
163
154
|
simplecov_json_formatter (0.1.4)
|
|
164
|
-
stringio (3.1.
|
|
155
|
+
stringio (3.1.1)
|
|
165
156
|
strscan (3.1.0)
|
|
166
157
|
thor (1.3.1)
|
|
167
158
|
tzinfo (2.0.6)
|
|
@@ -169,7 +160,7 @@ GEM
|
|
|
169
160
|
unicode-display_width (2.5.0)
|
|
170
161
|
webrick (1.8.1)
|
|
171
162
|
yard (0.9.36)
|
|
172
|
-
zeitwerk (2.6.
|
|
163
|
+
zeitwerk (2.6.16)
|
|
173
164
|
|
|
174
165
|
PLATFORMS
|
|
175
166
|
aarch64-linux
|
|
@@ -182,11 +173,11 @@ PLATFORMS
|
|
|
182
173
|
|
|
183
174
|
DEPENDENCIES
|
|
184
175
|
always!
|
|
185
|
-
minitest (= 5.
|
|
176
|
+
minitest (= 5.24.1)
|
|
186
177
|
rake (= 13.2.1)
|
|
187
|
-
rspec-rails (= 6.1.
|
|
178
|
+
rspec-rails (= 6.1.3)
|
|
188
179
|
rubocop (= 1.64.1)
|
|
189
|
-
rubocop-rspec (=
|
|
180
|
+
rubocop-rspec (= 3.0.2)
|
|
190
181
|
simplecov (= 0.22.0)
|
|
191
182
|
simplecov-cobertura (= 2.1.0)
|
|
192
183
|
yard (= 0.9.36)
|
data/README.md
CHANGED
|
@@ -15,9 +15,9 @@ This simple Ruby gem helps you run a loop forever, in a background thread.
|
|
|
15
15
|
|
|
16
16
|
```ruby
|
|
17
17
|
require 'always'
|
|
18
|
-
# Prepare, with five threads
|
|
19
|
-
a = Always.new(5
|
|
20
|
-
# Start them all together spinning forever:
|
|
18
|
+
# Prepare, with five threads:
|
|
19
|
+
a = Always.new(5)
|
|
20
|
+
# Start them all together spinning forever with 30-seconds delay between cycles:
|
|
21
21
|
a.start do
|
|
22
22
|
puts "I'm alive"
|
|
23
23
|
end
|
|
@@ -25,6 +25,18 @@ end
|
|
|
25
25
|
a.stop
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
You may be interested to get the backtraces of the exceptions that
|
|
29
|
+
happened most recently:
|
|
30
|
+
|
|
31
|
+
```ruby
|
|
32
|
+
# Keep the last 10 error backtraces in memory:
|
|
33
|
+
a = Always.new(5, max_backtraces: 10)
|
|
34
|
+
# Retrieve them:
|
|
35
|
+
p a.backtraces
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
That's it.
|
|
39
|
+
|
|
28
40
|
## How to contribute
|
|
29
41
|
|
|
30
42
|
Read
|
data/always.gemspec
CHANGED
|
@@ -26,7 +26,7 @@ Gem::Specification.new do |s|
|
|
|
26
26
|
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
|
27
27
|
s.required_ruby_version = '>=3.2'
|
|
28
28
|
s.name = 'always'
|
|
29
|
-
s.version = '0.0.
|
|
29
|
+
s.version = '0.0.5'
|
|
30
30
|
s.license = 'MIT'
|
|
31
31
|
s.summary = 'A simple Ruby framework that spins a loop forever, in a background thread'
|
|
32
32
|
s.description =
|
data/lib/always.rb
CHANGED
|
@@ -33,29 +33,37 @@ require 'concurrent/atom'
|
|
|
33
33
|
# puts 'Hello, world!
|
|
34
34
|
# end
|
|
35
35
|
#
|
|
36
|
-
# Then, in order stop them all together:
|
|
36
|
+
# Then, in order to stop them all together:
|
|
37
37
|
#
|
|
38
38
|
# a.stop
|
|
39
39
|
#
|
|
40
40
|
# It's possible to get a quick summary of the thread pool, by calling +to_s+.
|
|
41
|
+
# The result will be a +"T/C/E"+ string, where +T+ is the total number of
|
|
42
|
+
# currently running threads, +C+ is the total number of all cycles
|
|
43
|
+
# so far, and +E+ is the total number of all errors seen so far.
|
|
41
44
|
#
|
|
42
45
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
43
46
|
# Copyright:: Copyright (c) 2024 Yegor Bugayenko
|
|
44
47
|
# License:: MIT
|
|
45
48
|
class Always
|
|
49
|
+
attr_reader :backtraces
|
|
50
|
+
|
|
46
51
|
# The version of the framework.
|
|
47
|
-
VERSION = '0.0.
|
|
52
|
+
VERSION = '0.0.5'
|
|
48
53
|
|
|
49
54
|
# Constructor.
|
|
50
55
|
# @param [Integer] total The number of threads to run
|
|
51
|
-
|
|
56
|
+
# @param [Integer] max_backtraces How many backtraces to keep in memory?
|
|
57
|
+
def initialize(total, max_backtraces: 32)
|
|
52
58
|
raise "The number of threads (#{total}) must be positive" unless total.positive?
|
|
53
59
|
|
|
54
60
|
@total = total
|
|
55
61
|
@on_error = nil
|
|
56
62
|
@threads = []
|
|
63
|
+
@backtraces = []
|
|
57
64
|
@cycles = Concurrent::Atom.new(0)
|
|
58
65
|
@errors = Concurrent::Atom.new(0)
|
|
66
|
+
@max_backtraces = max_backtraces
|
|
59
67
|
end
|
|
60
68
|
|
|
61
69
|
# What to do when an exception occurs?
|
|
@@ -76,23 +84,29 @@ class Always
|
|
|
76
84
|
self
|
|
77
85
|
end
|
|
78
86
|
|
|
79
|
-
# Start them all.
|
|
87
|
+
# Start them all and let them run forever (until the +stop+ method is called).
|
|
80
88
|
# @param [Integer] pause The delay between cycles, in seconds
|
|
81
89
|
def start(pause = 0, &)
|
|
82
90
|
raise 'It is running now, call .stop() first' unless @threads.empty?
|
|
83
91
|
|
|
84
92
|
(0..@total - 1).each do |i|
|
|
85
93
|
@threads[i] = Thread.new do
|
|
86
|
-
body(
|
|
87
|
-
@cycles.swap { |c| c + 1 }
|
|
94
|
+
body(pause, &)
|
|
88
95
|
end
|
|
89
96
|
end
|
|
90
97
|
end
|
|
91
98
|
|
|
92
99
|
# Stop them all.
|
|
93
100
|
def stop
|
|
94
|
-
@threads.
|
|
95
|
-
|
|
101
|
+
raise 'It is not running now, call .start() first' if @threads.empty?
|
|
102
|
+
|
|
103
|
+
@threads.delete_if do |t|
|
|
104
|
+
t.kill
|
|
105
|
+
sleep(0.001) while t.alive?
|
|
106
|
+
true
|
|
107
|
+
end
|
|
108
|
+
@cycles.swap { |_| 0 }
|
|
109
|
+
@errors.swap { |_| 0 }
|
|
96
110
|
end
|
|
97
111
|
|
|
98
112
|
# Represent its internal state as a string.
|
|
@@ -106,15 +120,11 @@ class Always
|
|
|
106
120
|
private
|
|
107
121
|
|
|
108
122
|
# rubocop:disable Lint/RescueException
|
|
109
|
-
def body(
|
|
123
|
+
def body(pause, &)
|
|
110
124
|
loop do
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
@errors.swap { |c| c + 1 }
|
|
115
|
-
@on_error&.call(e, idx)
|
|
116
|
-
end
|
|
117
|
-
sleep(pause)
|
|
125
|
+
one(&)
|
|
126
|
+
@cycles.swap { |c| c + 1 }
|
|
127
|
+
sleep(pause) unless pause.zero?
|
|
118
128
|
rescue Exception
|
|
119
129
|
# If we reach this point, we must not even try to
|
|
120
130
|
# do anything. Here we must quietly ignore everything
|
|
@@ -122,4 +132,15 @@ class Always
|
|
|
122
132
|
end
|
|
123
133
|
end
|
|
124
134
|
# rubocop:enable Lint/RescueException
|
|
135
|
+
|
|
136
|
+
# rubocop:disable Lint/RescueException
|
|
137
|
+
def one
|
|
138
|
+
yield
|
|
139
|
+
rescue Exception => e
|
|
140
|
+
@errors.swap { |c| c + 1 }
|
|
141
|
+
@backtraces << e
|
|
142
|
+
@backtraces.shift if @backtraces.size > @max_backtraces
|
|
143
|
+
@on_error&.call(e)
|
|
144
|
+
end
|
|
145
|
+
# rubocop:enable Lint/RescueException
|
|
125
146
|
end
|
data/test/test_always.rb
CHANGED
|
@@ -39,7 +39,7 @@ class TestAlways < Minitest::Test
|
|
|
39
39
|
def test_with_error
|
|
40
40
|
a = Always.new(5)
|
|
41
41
|
failures = 0
|
|
42
|
-
a.on_error { |_e
|
|
42
|
+
a.on_error { |_e| failures += 1 }.start do
|
|
43
43
|
raise 'intentionally'
|
|
44
44
|
end
|
|
45
45
|
sleep(0.1)
|
|
@@ -47,13 +47,37 @@ class TestAlways < Minitest::Test
|
|
|
47
47
|
assert(failures.positive?)
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
def
|
|
51
|
-
|
|
52
|
-
a.
|
|
53
|
-
|
|
50
|
+
def test_read_backtraces
|
|
51
|
+
max = 5
|
|
52
|
+
a = Always.new(5, max_backtraces: max)
|
|
53
|
+
failures = 0
|
|
54
|
+
a.on_error { |_e| failures += 1 }.start do
|
|
55
|
+
raise 'intentionally'
|
|
54
56
|
end
|
|
55
|
-
|
|
57
|
+
sleep(0.1)
|
|
58
|
+
a.stop
|
|
59
|
+
assert(failures.positive?)
|
|
60
|
+
assert_equal(max, a.backtraces.size)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_converts_to_string
|
|
64
|
+
n = 6
|
|
65
|
+
a = Always.new(6)
|
|
66
|
+
a.start { sleep(0.01) }
|
|
67
|
+
sleep(0.1)
|
|
68
|
+
threads, cycles, errors = a.to_s.split('/')
|
|
69
|
+
assert_equal(n, threads.to_i)
|
|
70
|
+
assert(cycles.to_i.positive?)
|
|
71
|
+
assert(errors.to_i.zero?)
|
|
72
|
+
a.stop
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def test_stops_correctly
|
|
76
|
+
a = Always.new(6)
|
|
77
|
+
a.start { sleep(0.01) }
|
|
78
|
+
sleep(0.01)
|
|
56
79
|
a.stop
|
|
80
|
+
assert_equal('0/0/0', a.to_s)
|
|
57
81
|
end
|
|
58
82
|
|
|
59
83
|
def test_with_counter
|
|
@@ -66,4 +90,17 @@ class TestAlways < Minitest::Test
|
|
|
66
90
|
a.stop
|
|
67
91
|
assert(done.positive?)
|
|
68
92
|
end
|
|
93
|
+
|
|
94
|
+
def test_with_broken_syntax
|
|
95
|
+
a = Always.new(1)
|
|
96
|
+
failures = 0
|
|
97
|
+
a.on_error { |_e| failures += 1 }.start do
|
|
98
|
+
eval('broken$ruby$syntax')
|
|
99
|
+
end
|
|
100
|
+
sleep(0.1)
|
|
101
|
+
_, _, errors = a.to_s.split('/')
|
|
102
|
+
assert(!errors.to_i.zero?)
|
|
103
|
+
assert(!failures.zero?)
|
|
104
|
+
a.stop
|
|
105
|
+
end
|
|
69
106
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: always
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yegor Bugayenko
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-
|
|
11
|
+
date: 2024-07-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: concurrent-ruby
|