exceptional_synchrony 1.1.1 → 1.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 +4 -4
- data/.gitignore +1 -0
- data/.jenkins/Jenkinsfile +58 -0
- data/.jenkins/ruby_build_pod.yml +19 -0
- data/CHANGELOG.md +14 -1
- data/Gemfile +1 -0
- data/Gemfile.lock +48 -41
- data/lib/exceptional_synchrony/event_machine_proxy.rb +44 -7
- data/lib/exceptional_synchrony/version.rb +1 -1
- data/test/test_helper.rb +5 -0
- data/test/unit/event_machine_proxy_test.rb +59 -15
- metadata +3 -2
- data/semaphore_ci/setup.sh +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f13da539398611f0cfabb6439072114ef3904d89028205ee79bd7c17cb439ca
|
4
|
+
data.tar.gz: 1089857cd4e512dd3717b403163a3f74d53bc2cf0902bd13890fb842c7a9644b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb0ce260721a479fe42118cfe78c5e06a45e36801e7d3cc25eb823baeff7693c46071bb07e314e3f51aad2b5ed3d61373219c1015b2f9cc0ff28bd1a116f8bb7
|
7
|
+
data.tar.gz: 81ed89b82782b3f80494b999efeb3d629834c1a4ab1e9e31ab446e4e7a58da0d915252e6f3e401945e1f2be82c20bc3d1f59e34667805180199ee0c2758f91fd
|
data/.gitignore
CHANGED
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/bin/groovy
|
2
|
+
@Library('jenkins-pipeline@v0.4.5')
|
3
|
+
import com.invoca.docker.*;
|
4
|
+
pipeline {
|
5
|
+
agent {
|
6
|
+
kubernetes {
|
7
|
+
defaultContainer "ruby"
|
8
|
+
yamlFile ".jenkins/ruby_build_pod.yml"
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
environment {
|
13
|
+
GITHUB_TOKEN = credentials('github_token')
|
14
|
+
GITHUB_KEY = credentials('github_key')
|
15
|
+
BUNDLE_GEM__FURY__IO = credentials('gemfury_deploy_token')
|
16
|
+
}
|
17
|
+
|
18
|
+
stages {
|
19
|
+
stage('Setup') {
|
20
|
+
steps {
|
21
|
+
updateGitHubStatus('clean-build', 'pending', 'Unit tests.')
|
22
|
+
script {
|
23
|
+
sh '''
|
24
|
+
# get SSH setup inside the container
|
25
|
+
eval `ssh-agent -s`
|
26
|
+
echo "$GITHUB_KEY" | ssh-add -
|
27
|
+
mkdir -p /root/.ssh
|
28
|
+
ssh-keyscan -t rsa github.com > /root/.ssh/known_hosts
|
29
|
+
bundle install
|
30
|
+
''' }
|
31
|
+
}
|
32
|
+
}
|
33
|
+
stage('Unit Test') {
|
34
|
+
steps {
|
35
|
+
script {
|
36
|
+
sh 'bundle exec rake'
|
37
|
+
}
|
38
|
+
}
|
39
|
+
post {
|
40
|
+
always { junit '*/reports/*.xml' }
|
41
|
+
success { updateGitHubStatus('clean-build', 'success', 'Unit tests.') }
|
42
|
+
failure { updateGitHubStatus('clean-build', 'failure', 'Unit tests.') }
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
void updateGitHubStatus(String context, String status, String description) {
|
49
|
+
gitHubStatus([
|
50
|
+
repoSlug: 'Invoca/exceptional_synchrony',
|
51
|
+
sha: env.GIT_COMMIT,
|
52
|
+
description: description,
|
53
|
+
context: context,
|
54
|
+
targetURL: env.RUN_DISPLAY_URL,
|
55
|
+
token: env.GITHUB_TOKEN,
|
56
|
+
status: status
|
57
|
+
])
|
58
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
---
|
2
|
+
apiVersion: v1
|
3
|
+
kind: Pod
|
4
|
+
metadata:
|
5
|
+
labels:
|
6
|
+
jenkins/exceptional-synchrony: 'true'
|
7
|
+
namespace: jenkins
|
8
|
+
name: exceptional-synchrony
|
9
|
+
spec:
|
10
|
+
containers:
|
11
|
+
- name: ruby
|
12
|
+
image: ruby:2.6.5
|
13
|
+
tty: true
|
14
|
+
resources:
|
15
|
+
requests:
|
16
|
+
memory: "100Mi"
|
17
|
+
command:
|
18
|
+
- cat
|
19
|
+
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# CHANGELOG for `
|
1
|
+
# CHANGELOG for `exception_synchrony`
|
2
2
|
|
3
3
|
Inspired by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
4
4
|
|
@@ -9,3 +9,16 @@ All notable changes to this project will be documented in this file.
|
|
9
9
|
- Replace hobo_support with invoca_utils
|
10
10
|
|
11
11
|
[1.1.1]: https://github.com/Invoca/exceptional_synchrony/compare/v1.1.0...v1.1.1
|
12
|
+
|
13
|
+
## [1.2.0] - 2020-06-02
|
14
|
+
### Changed
|
15
|
+
- If `EMP.run` rescues an exception, previous versions would simply log the exception and continue.
|
16
|
+
Instead this version has an `on_error` option with possible values `:log` and `:raise`.
|
17
|
+
It defaults to `:log` and in that case, as before, logs any rescued `StandardError` exception and continues.
|
18
|
+
When `on_error` is set to `:raise`, the method raises a `FatalRunError` wrapper around the rescued exception.
|
19
|
+
This `FatalRunError` exception does not derive from `StandardError`, so it will not be erroneously rescued by any
|
20
|
+
registered `EMP.error_handler`. Instead it should be rescued at the outer edge of the process.
|
21
|
+
We expect that outer edge handler to log the exception chain (the wrapper plus nested `cause` exception(s))
|
22
|
+
and exit the process with a non-0 status code.
|
23
|
+
|
24
|
+
[1.2.0]: https://github.com/Invoca/exceptional_synchrony/compare/v1.1.1...v1.2.0
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
exceptional_synchrony (1.
|
4
|
+
exceptional_synchrony (1.2.0)
|
5
5
|
em-http-request
|
6
6
|
em-synchrony
|
7
7
|
eventmachine
|
@@ -11,39 +11,41 @@ PATH
|
|
11
11
|
GEM
|
12
12
|
remote: https://rubygems.org/
|
13
13
|
specs:
|
14
|
-
actionmailer (
|
15
|
-
actionpack (=
|
16
|
-
actionview (=
|
17
|
-
activejob (=
|
14
|
+
actionmailer (6.0.3.1)
|
15
|
+
actionpack (= 6.0.3.1)
|
16
|
+
actionview (= 6.0.3.1)
|
17
|
+
activejob (= 6.0.3.1)
|
18
18
|
mail (~> 2.5, >= 2.5.4)
|
19
|
-
rails-dom-testing (~>
|
20
|
-
actionpack (
|
21
|
-
actionview (=
|
22
|
-
activesupport (=
|
23
|
-
rack (~>
|
24
|
-
rack-test (
|
25
|
-
rails-dom-testing (~>
|
26
|
-
rails-html-sanitizer (~> 1.0, >= 1.0
|
27
|
-
actionview (
|
28
|
-
activesupport (=
|
19
|
+
rails-dom-testing (~> 2.0)
|
20
|
+
actionpack (6.0.3.1)
|
21
|
+
actionview (= 6.0.3.1)
|
22
|
+
activesupport (= 6.0.3.1)
|
23
|
+
rack (~> 2.0, >= 2.0.8)
|
24
|
+
rack-test (>= 0.6.3)
|
25
|
+
rails-dom-testing (~> 2.0)
|
26
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
27
|
+
actionview (6.0.3.1)
|
28
|
+
activesupport (= 6.0.3.1)
|
29
29
|
builder (~> 3.1)
|
30
|
-
|
31
|
-
rails-dom-testing (~>
|
32
|
-
rails-html-sanitizer (~> 1.
|
33
|
-
activejob (
|
34
|
-
activesupport (=
|
35
|
-
globalid (>= 0.3.
|
36
|
-
activesupport (
|
37
|
-
|
30
|
+
erubi (~> 1.4)
|
31
|
+
rails-dom-testing (~> 2.0)
|
32
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
33
|
+
activejob (6.0.3.1)
|
34
|
+
activesupport (= 6.0.3.1)
|
35
|
+
globalid (>= 0.3.6)
|
36
|
+
activesupport (6.0.3.1)
|
37
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
38
|
+
i18n (>= 0.7, < 2)
|
38
39
|
minitest (~> 5.1)
|
39
|
-
thread_safe (~> 0.3, >= 0.3.4)
|
40
40
|
tzinfo (~> 1.1)
|
41
|
+
zeitwerk (~> 2.2, >= 2.2.2)
|
41
42
|
addressable (2.7.0)
|
42
43
|
public_suffix (>= 2.0.2, < 5.0)
|
44
|
+
ansi (1.5.0)
|
43
45
|
builder (3.2.4)
|
44
46
|
coderay (1.1.2)
|
45
47
|
concurrent-ruby (1.1.6)
|
46
|
-
contextual_logger (0.
|
48
|
+
contextual_logger (0.8.0)
|
47
49
|
activesupport
|
48
50
|
json
|
49
51
|
cookiejar (0.3.3)
|
@@ -60,20 +62,20 @@ GEM
|
|
60
62
|
eventmachine (>= 1.0.0.beta.4)
|
61
63
|
em-synchrony (1.0.6)
|
62
64
|
eventmachine (>= 1.0.0.beta.1)
|
63
|
-
|
65
|
+
erubi (1.9.0)
|
64
66
|
eventmachine (1.2.7)
|
65
|
-
exception_handling (2.4.
|
66
|
-
actionmailer (
|
67
|
-
actionpack (
|
68
|
-
activesupport (
|
69
|
-
contextual_logger
|
67
|
+
exception_handling (2.4.3)
|
68
|
+
actionmailer (>= 4.2, < 7.0)
|
69
|
+
actionpack (>= 4.2, < 7.0)
|
70
|
+
activesupport (>= 4.2, < 7.0)
|
71
|
+
contextual_logger (~> 0.7)
|
70
72
|
eventmachine (~> 1.0)
|
71
73
|
invoca-utils (~> 0.3)
|
72
74
|
globalid (0.4.2)
|
73
75
|
activesupport (>= 4.2.0)
|
74
76
|
hashdiff (1.0.1)
|
75
77
|
http_parser.rb (0.6.0)
|
76
|
-
i18n (
|
78
|
+
i18n (1.8.2)
|
77
79
|
concurrent-ruby (~> 1.0)
|
78
80
|
invoca-utils (0.3.0)
|
79
81
|
json (2.3.0)
|
@@ -86,25 +88,28 @@ GEM
|
|
86
88
|
mini_mime (1.0.2)
|
87
89
|
mini_portile2 (2.4.0)
|
88
90
|
minitest (5.14.0)
|
91
|
+
minitest-reporters (1.4.2)
|
92
|
+
ansi
|
93
|
+
builder
|
94
|
+
minitest (>= 5.0)
|
95
|
+
ruby-progressbar
|
89
96
|
nokogiri (1.10.9)
|
90
97
|
mini_portile2 (~> 2.4.0)
|
91
98
|
pry (0.13.1)
|
92
99
|
coderay (~> 1.1)
|
93
100
|
method_source (~> 1.0)
|
94
101
|
public_suffix (4.0.4)
|
95
|
-
rack (
|
96
|
-
rack-test (
|
97
|
-
rack (>= 1.0)
|
98
|
-
rails-
|
99
|
-
activesupport (>= 4.2.0
|
100
|
-
|
101
|
-
activesupport (>= 4.2.0, < 5.0)
|
102
|
-
nokogiri (~> 1.6)
|
103
|
-
rails-deprecated_sanitizer (>= 1.0.1)
|
102
|
+
rack (2.2.2)
|
103
|
+
rack-test (1.1.0)
|
104
|
+
rack (>= 1.0, < 3)
|
105
|
+
rails-dom-testing (2.0.3)
|
106
|
+
activesupport (>= 4.2.0)
|
107
|
+
nokogiri (>= 1.6)
|
104
108
|
rails-html-sanitizer (1.3.0)
|
105
109
|
loofah (~> 2.3)
|
106
110
|
rake (13.0.1)
|
107
111
|
rr (1.2.1)
|
112
|
+
ruby-progressbar (1.10.1)
|
108
113
|
safe_yaml (1.0.5)
|
109
114
|
thor (1.0.1)
|
110
115
|
thread_safe (0.3.6)
|
@@ -114,6 +119,7 @@ GEM
|
|
114
119
|
addressable (>= 2.3.6)
|
115
120
|
crack (>= 0.3.2)
|
116
121
|
hashdiff
|
122
|
+
zeitwerk (2.3.0)
|
117
123
|
|
118
124
|
PLATFORMS
|
119
125
|
ruby
|
@@ -121,6 +127,7 @@ PLATFORMS
|
|
121
127
|
DEPENDENCIES
|
122
128
|
exceptional_synchrony!
|
123
129
|
minitest
|
130
|
+
minitest-reporters
|
124
131
|
pry
|
125
132
|
rake
|
126
133
|
rr (~> 1.2)
|
@@ -5,6 +5,10 @@ require 'em-http'
|
|
5
5
|
require 'em-synchrony/em-http'
|
6
6
|
|
7
7
|
module ExceptionalSynchrony
|
8
|
+
# It is important for this exception to be inherited from Exception so that
|
9
|
+
# when thrown it does not get caught by the EventMachine.error_handler.
|
10
|
+
class FatalRunError < Exception; end
|
11
|
+
|
8
12
|
class EventMachineProxy
|
9
13
|
|
10
14
|
attr_reader :connection
|
@@ -64,13 +68,14 @@ module ExceptionalSynchrony
|
|
64
68
|
@proxy_class.connect(server, port, handler, *args, &block)
|
65
69
|
end
|
66
70
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
71
|
+
# The on_error option has these possible values:
|
72
|
+
# :log - log any rescued StandardError exceptions and continue
|
73
|
+
# :raise - raise FatalRunError for any rescued StandardError exceptions
|
74
|
+
def run(on_error: :log, &block)
|
75
|
+
case on_error
|
76
|
+
when :log then run_with_error_logging(&block)
|
77
|
+
when :raise then run_with_error_raising(&block)
|
78
|
+
else raise ArgumentError, "Invalid on_error: #{on_error.inspect}, must be :log or :raise"
|
74
79
|
end
|
75
80
|
end
|
76
81
|
|
@@ -108,6 +113,38 @@ module ExceptionalSynchrony
|
|
108
113
|
yield
|
109
114
|
end
|
110
115
|
end
|
116
|
+
|
117
|
+
def rescue_exceptions_and_ensure_exit(context)
|
118
|
+
yield
|
119
|
+
rescue StandardError => ex
|
120
|
+
# Raise a non-StandardError so that not caught by EM.error_handler.
|
121
|
+
# Expecting rescued exception to be stored in this new exception's cause.
|
122
|
+
raise FatalRunError, "Fatal EventMachine #{context} error\n#{ex.class.name}: #{ex.message}"
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def run_with_error_logging(&block)
|
128
|
+
ensure_completely_safe("run_with_error_logging") do
|
129
|
+
if @proxy_class.respond_to?(:synchrony)
|
130
|
+
@proxy_class.synchrony(&block)
|
131
|
+
else
|
132
|
+
@proxy_class.run(&block)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def run_with_error_raising(&block)
|
138
|
+
run_block = -> { rescue_exceptions_and_ensure_exit("run_with_error_raising", &block) }
|
139
|
+
|
140
|
+
rescue_exceptions_and_ensure_exit("run_with_error_raising") do
|
141
|
+
if @proxy_class.respond_to?(:synchrony)
|
142
|
+
@proxy_class.synchrony(&run_block)
|
143
|
+
else
|
144
|
+
@proxy_class.run(&run_block)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
111
148
|
end
|
112
149
|
|
113
150
|
EMP = EventMachineProxy.new(EventMachine, EventMachine::HttpRequest)
|
data/test/test_helper.rb
CHANGED
@@ -7,6 +7,11 @@ require_relative '../lib/exceptional_synchrony.rb'
|
|
7
7
|
|
8
8
|
require 'minitest/autorun' or raise "Already loaded minitest?"
|
9
9
|
require 'minitest/pride'
|
10
|
+
require 'minitest/reporters'
|
11
|
+
Minitest::Reporters.use! [
|
12
|
+
Minitest::Reporters::DefaultReporter.new,
|
13
|
+
Minitest::Reporters::JUnitReporter.new
|
14
|
+
]
|
10
15
|
require 'webmock'
|
11
16
|
require 'webmock/minitest'
|
12
17
|
require 'rr'
|
@@ -3,10 +3,31 @@ require_relative '../test_helper'
|
|
3
3
|
describe ExceptionalSynchrony::EventMachineProxy do
|
4
4
|
include TestHelper
|
5
5
|
|
6
|
+
class RunProxyMock
|
7
|
+
class << self
|
8
|
+
def run(&block)
|
9
|
+
block.call
|
10
|
+
:run
|
11
|
+
end
|
12
|
+
|
13
|
+
def error_handler
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class SynchronyProxyMock < RunProxyMock
|
19
|
+
class << self
|
20
|
+
def synchrony(&block)
|
21
|
+
block.call
|
22
|
+
:synchrony
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
6
27
|
before do
|
7
28
|
@em = ExceptionalSynchrony::EventMachineProxy.new(EventMachine, nil)
|
8
29
|
@yielded_value = nil
|
9
|
-
@block =
|
30
|
+
@block = -> (value) { @yielded_value = value }
|
10
31
|
end
|
11
32
|
|
12
33
|
it "should proxy add_timer" do
|
@@ -106,27 +127,50 @@ describe ExceptionalSynchrony::EventMachineProxy do
|
|
106
127
|
end
|
107
128
|
end
|
108
129
|
|
109
|
-
|
110
|
-
describe "
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
130
|
+
{ synchrony: SynchronyProxyMock, run: RunProxyMock }.each do |method, proxy_mock|
|
131
|
+
describe "run" do
|
132
|
+
before do
|
133
|
+
@proxy = ExceptionalSynchrony::EventMachineProxy.new(proxy_mock, nil)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should raise ArgumentError if on_error has invalid value" do
|
137
|
+
assert_raises(ArgumentError, "Invalid on_error: :ignore, must be :log or :raise") do
|
138
|
+
@proxy.run(on_error: :ignore)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe "without error" do
|
143
|
+
[:log, :raise].each do |on_error|
|
144
|
+
describe "when using #{method} and on_error = #{on_error}" do
|
145
|
+
it "should dispatch to the proxy's synchrony method instead of run iff synchrony" do
|
146
|
+
dispatched = false
|
147
|
+
assert_equal method, (@proxy.run(on_error: on_error) { dispatched = true })
|
148
|
+
assert_equal true, dispatched
|
116
149
|
end
|
117
150
|
end
|
151
|
+
end
|
152
|
+
end
|
118
153
|
|
119
|
-
|
120
|
-
|
121
|
-
|
154
|
+
describe "with error" do
|
155
|
+
before do
|
156
|
+
set_test_const('ExceptionalSynchrony::EventMachineProxy::WRAP_WITH_ENSURE_COMPLETELY_SAFE', true)
|
122
157
|
end
|
123
158
|
|
124
|
-
|
159
|
+
describe "when using #{method} and on_error = :log" do
|
160
|
+
it "should rescue any exceptions and log them" do
|
161
|
+
mock(ExceptionHandling).log_error(EXCEPTION, "run_with_error_logging", {})
|
125
162
|
|
126
|
-
|
163
|
+
@proxy.run(on_error: :log) { raise EXCEPTION }
|
164
|
+
end
|
165
|
+
end
|
127
166
|
|
128
|
-
|
129
|
-
|
167
|
+
describe "when using #{method} and on_error = :raise" do
|
168
|
+
it "should rescue any exceptions and raise FatalRunError" do
|
169
|
+
assert_raises(ExceptionalSynchrony::FatalRunError, "Fatal EventMachine run error") do
|
170
|
+
@proxy.run(on_error: :raise) { raise EXCEPTION }
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
130
174
|
end
|
131
175
|
end
|
132
176
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: exceptional_synchrony
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Invoca
|
@@ -88,6 +88,8 @@ extra_rdoc_files: []
|
|
88
88
|
files:
|
89
89
|
- ".dependabot/config.yml"
|
90
90
|
- ".gitignore"
|
91
|
+
- ".jenkins/Jenkinsfile"
|
92
|
+
- ".jenkins/ruby_build_pod.yml"
|
91
93
|
- ".ruby-gemset"
|
92
94
|
- ".ruby-version"
|
93
95
|
- CHANGELOG.md
|
@@ -102,7 +104,6 @@ files:
|
|
102
104
|
- lib/exceptional_synchrony/limited_work_queue.rb
|
103
105
|
- lib/exceptional_synchrony/parallel_sync.rb
|
104
106
|
- lib/exceptional_synchrony/version.rb
|
105
|
-
- semaphore_ci/setup.sh
|
106
107
|
- test/test_helper.rb
|
107
108
|
- test/unit/callback_exceptions_test.rb
|
108
109
|
- test/unit/event_machine_proxy_test.rb
|
data/semaphore_ci/setup.sh
DELETED