serf 0.10.0 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +21 -0
- data/.travis.yml +7 -0
- data/Gemfile +20 -26
- data/Guardfile +16 -0
- data/NOTICE.txt +1 -1
- data/README.md +223 -207
- data/Rakefile +3 -18
- data/lib/serf/builder.rb +31 -136
- data/lib/serf/errors/policy_failure.rb +10 -0
- data/lib/serf/middleware/error_handler.rb +53 -0
- data/lib/serf/middleware/parcel_freezer.rb +36 -0
- data/lib/serf/middleware/parcel_masher.rb +39 -0
- data/lib/serf/middleware/policy_checker.rb +31 -0
- data/lib/serf/middleware/uuid_tagger.rb +13 -11
- data/lib/serf/parcel_builder.rb +30 -0
- data/lib/serf/serfer.rb +27 -66
- data/lib/serf/util/error_handling.rb +13 -36
- data/lib/serf/util/protected_call.rb +2 -2
- data/lib/serf/util/uuidable.rb +14 -38
- data/lib/serf/version.rb +1 -1
- data/schemas/{caught_exception_event.json → serf/events/caught_error.json} +4 -7
- data/serf.gemspec +22 -101
- data/spec/serf/builder_spec.rb +44 -0
- data/spec/serf/errors/policy_failure_spec.rb +11 -0
- data/spec/serf/middleware/error_handler_spec.rb +48 -0
- data/spec/serf/middleware/parcel_freezer_spec.rb +20 -0
- data/spec/serf/middleware/parcel_masher_spec.rb +30 -0
- data/spec/serf/middleware/policy_checker_spec.rb +70 -0
- data/spec/serf/middleware/uuid_tagger_spec.rb +32 -0
- data/spec/serf/parcel_builder_spec.rb +46 -0
- data/spec/serf/serfer_spec.rb +61 -0
- data/spec/serf/util/error_handling_spec.rb +35 -0
- data/spec/serf/util/null_object_spec.rb +26 -0
- data/spec/serf/util/options_extraction_spec.rb +62 -0
- data/spec/serf/util/protected_call_spec.rb +33 -0
- data/spec/serf/util/uuidable_spec.rb +56 -0
- data/spec/serf_spec.rb +1 -4
- data/spec/spec_helper.rb +3 -0
- data/spec/support/error_handling_wrapper.rb +5 -0
- data/spec/support/factories.rb +32 -0
- data/spec/support/failing_policy.rb +9 -0
- data/spec/support/json_schema_tester.rb +14 -0
- data/spec/support/options_extraction_wrapper.rb +10 -0
- data/spec/support/passing_policy.rb +7 -0
- data/spec/support/protected_call_wrapper.rb +5 -0
- metadata +81 -131
- data/.document +0 -5
- data/.rspec +0 -1
- data/Gemfile.lock +0 -58
- data/docs/thread_pools.txt +0 -16
- data/lib/serf/command.rb +0 -79
- data/lib/serf/error.rb +0 -11
- data/lib/serf/errors/not_found.rb +0 -8
- data/lib/serf/middleware/girl_friday_async.rb +0 -39
- data/lib/serf/middleware/masherize.rb +0 -25
- data/lib/serf/routing/regexp_matcher.rb +0 -35
- data/lib/serf/routing/route.rb +0 -35
- data/lib/serf/routing/route_set.rb +0 -64
- data/schemas/message_accepted_event.json +0 -14
data/lib/serf/builder.rb
CHANGED
@@ -1,166 +1,61 @@
|
|
1
|
-
require 'serf/
|
2
|
-
require 'serf/
|
1
|
+
require 'serf/middleware/error_handler'
|
2
|
+
require 'serf/middleware/parcel_freezer'
|
3
|
+
require 'serf/middleware/parcel_masher'
|
4
|
+
require 'serf/middleware/policy_checker'
|
5
|
+
require 'serf/middleware/uuid_tagger'
|
3
6
|
require 'serf/serfer'
|
4
|
-
require 'serf/util/null_object'
|
5
7
|
require 'serf/util/options_extraction'
|
6
8
|
|
7
9
|
module Serf
|
8
10
|
|
9
|
-
##
|
10
|
-
# A Serf Builder that processes the SerfUp DSL to build a rack-like
|
11
|
-
# app to handlers that process received messages. This builder is
|
12
|
-
# implemented based on code from Rack::Builder.
|
13
|
-
#
|
14
|
-
# builder = Serf::Builder.parse_file 'examples/config.su'
|
15
|
-
# builder.to_app
|
16
|
-
#
|
17
|
-
# or
|
18
|
-
#
|
19
|
-
# builder = Serf::Builder.new do
|
20
|
-
# ... A SerfUp Config block here.
|
21
|
-
# end
|
22
|
-
# builder.to_app
|
23
|
-
#
|
24
11
|
class Builder
|
25
12
|
include Serf::Util::OptionsExtraction
|
26
13
|
|
27
|
-
attr_reader :serfer_factory
|
28
|
-
attr_reader :route_set_factory
|
29
|
-
attr_reader :route_factory
|
30
|
-
|
31
|
-
def self.parse_file(config)
|
32
|
-
cfgfile = ::File.read(config)
|
33
|
-
builder = eval "Serf::Builder.new {\n" + cfgfile + "\n}",
|
34
|
-
TOPLEVEL_BINDING, config
|
35
|
-
return builder
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.app(*args, &block)
|
39
|
-
new(*args, &block).to_app
|
40
|
-
end
|
41
|
-
|
42
14
|
def initialize(*args, &block)
|
43
15
|
extract_options! args
|
44
16
|
|
45
|
-
|
46
|
-
@serfer_factory = opts :serfer_factory, Serf::Serfer
|
47
|
-
@route_set_factory = opts :route_set_factory, Serf::Routing::RouteSet
|
48
|
-
@route_factory = opts :route_factory, Serf::Routing::Route
|
49
|
-
|
50
|
-
# List of middleware to be executed (non-built form)
|
17
|
+
@run = opts :interactor
|
51
18
|
@use = []
|
19
|
+
@policy_chain = opts :policy_chain, []
|
52
20
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
@default_policies = []
|
59
|
-
|
60
|
-
# The current matcher
|
61
|
-
@matcher = nil
|
62
|
-
|
63
|
-
# Current policies to be run (PRE-built)
|
64
|
-
@policies = []
|
65
|
-
|
66
|
-
# configure based on a given block.
|
67
|
-
instance_eval(&block) if block_given?
|
21
|
+
if block_given?
|
22
|
+
instance_eval(&block)
|
23
|
+
else
|
24
|
+
use_defaults
|
25
|
+
end
|
68
26
|
end
|
69
27
|
|
70
28
|
##
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
29
|
+
# Set a default chain of the following:
|
30
|
+
#
|
31
|
+
# use Serf::Middleware::ParcelMasher
|
32
|
+
# use Serf::Middleware::UuidTagger
|
33
|
+
# use Serf::Middleware::ParcelFreezer
|
34
|
+
# use Serf::Middleware::ErrorHandler
|
35
|
+
# use Serf::Middleware::PolicyChecker, @policy_chain
|
36
|
+
# use Serf::Serfer
|
74
37
|
#
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
38
|
+
def use_defaults
|
39
|
+
use Serf::Middleware::ParcelMasher
|
40
|
+
use Serf::Middleware::UuidTagger
|
41
|
+
use Serf::Middleware::ParcelFreezer
|
42
|
+
use Serf::Middleware::ErrorHandler
|
43
|
+
use Serf::Middleware::PolicyChecker, policy_chain: @policy_chain
|
44
|
+
use Serf::Serfer
|
80
45
|
end
|
81
46
|
|
82
|
-
##
|
83
|
-
# Append a rack-like middleware
|
84
|
-
#
|
85
|
-
# @param the middleware class
|
86
|
-
# @param *args the arguments to pass to middleware.new
|
87
|
-
# @param &block the block to pass to middleware.new
|
88
47
|
def use(middleware, *args, &block)
|
89
48
|
@use << proc { |app| middleware.new(app, *args, &block) }
|
90
49
|
end
|
91
50
|
|
92
|
-
|
93
|
-
|
94
|
-
#
|
95
|
-
# @param policy the policy factory to append
|
96
|
-
# @param *args the arguments to pass to the factory
|
97
|
-
# @param &block the block to pass to the factory
|
98
|
-
def policy(policy, *args, &block)
|
99
|
-
@policies << proc { policy.build(*args, &block) }
|
51
|
+
def run(interactor)
|
52
|
+
@run = interactor
|
100
53
|
end
|
101
54
|
|
102
|
-
def response_channel(channel); @response_channel = channel; end
|
103
|
-
def error_channel(channel); @error_channel = channel; end
|
104
|
-
def logger(logger); @logger = logger; end
|
105
|
-
|
106
|
-
##
|
107
|
-
# DSL Method to change our current context to use the given matcher.
|
108
|
-
#
|
109
|
-
def match(matcher)
|
110
|
-
@matcher = matcher
|
111
|
-
@policies = []
|
112
|
-
end
|
113
|
-
|
114
|
-
##
|
115
|
-
# @param command_factory the factory to invoke (in #to_app)
|
116
|
-
# @param *args the rest of the args to pass to command_factory#build method
|
117
|
-
# @param &block the block to pass to command_factory#build method
|
118
|
-
def run(command_factory, *args, &block)
|
119
|
-
raise 'No matcher defined yet' unless @matcher
|
120
|
-
# Create a local duplicate of the matcher and policies "snapshotted"
|
121
|
-
# at the time this method is called... so that snapshot is consistent
|
122
|
-
# for when the proc is called.
|
123
|
-
matcher = @matcher.dup
|
124
|
-
policies = @policies.dup
|
125
|
-
|
126
|
-
# This proc will be called in to_app when we actually go ahead and
|
127
|
-
# instantiate all the objects. By this point, route_set and
|
128
|
-
# default_policies passed to this proc will be ready, built.
|
129
|
-
@runs << proc { |route_set, default_policies|
|
130
|
-
route_set.add(
|
131
|
-
matcher,
|
132
|
-
route_factory.build(
|
133
|
-
command: command_factory.build(*args, &block),
|
134
|
-
policies: (policies.size > 0 ?
|
135
|
-
policies.map{ |p| p.call } :
|
136
|
-
default_policies)))
|
137
|
-
}
|
138
|
-
end
|
139
|
-
|
140
|
-
##
|
141
|
-
# Create our app.
|
142
|
-
#
|
143
55
|
def to_app
|
144
|
-
|
145
|
-
route_set = route_set_factory.build
|
146
|
-
# Build the default policies to be used if routes did not specify any.
|
147
|
-
default_policies = @default_policies.map{ |p| p.call }
|
148
|
-
# Add each route to the route_set
|
149
|
-
for run in @runs
|
150
|
-
run.call route_set, default_policies
|
151
|
-
end
|
152
|
-
# Create our serfer class
|
153
|
-
app = serfer_factory.build(
|
154
|
-
route_set: route_set,
|
155
|
-
response_channel: (@response_channel || Serf::Util::NullObject.new),
|
156
|
-
error_channel: (@error_channel || Serf::Util::NullObject.new),
|
157
|
-
logger: (@logger || Serf::Util::NullObject.new))
|
158
|
-
|
159
|
-
# We're going to inject middleware here.
|
160
|
-
app = @use.reverse.inject(app) { |a,e| e[a] } if @use.size > 0
|
161
|
-
|
162
|
-
return app
|
56
|
+
@use.reverse.inject(@run) { |a,e| e[a] }
|
163
57
|
end
|
164
58
|
|
165
59
|
end
|
60
|
+
|
166
61
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
|
3
|
+
require 'serf/parcel_builder'
|
4
|
+
require 'serf/util/error_handling'
|
5
|
+
require 'serf/util/uuidable'
|
6
|
+
|
7
|
+
module Serf
|
8
|
+
module Middleware
|
9
|
+
|
10
|
+
##
|
11
|
+
# Middleware to catch raised exceptions and return an error parcel
|
12
|
+
# instead.
|
13
|
+
#
|
14
|
+
class ErrorHandler
|
15
|
+
include Serf::Util::ErrorHandling
|
16
|
+
include Serf::Util::OptionsExtraction
|
17
|
+
|
18
|
+
attr_reader :app
|
19
|
+
attr_reader :parcel_builder
|
20
|
+
attr_reader :uuidable
|
21
|
+
|
22
|
+
##
|
23
|
+
# @param app the app
|
24
|
+
#
|
25
|
+
def initialize(app, *args)
|
26
|
+
extract_options! args
|
27
|
+
@app = app
|
28
|
+
|
29
|
+
# Tunable knobs
|
30
|
+
@parcel_builder = opts(:parcel_builder) { Serf::ParcelBuilder.new }
|
31
|
+
@uuidable = opts(:uuidable) { Serf::Util::Uuidable.new }
|
32
|
+
end
|
33
|
+
|
34
|
+
def call(parcel)
|
35
|
+
# Attempt to execute the app, catching errors
|
36
|
+
response_parcel, error_message = with_error_handling do
|
37
|
+
app.call parcel
|
38
|
+
end
|
39
|
+
|
40
|
+
# Return on success
|
41
|
+
return response_parcel if response_parcel
|
42
|
+
|
43
|
+
# We got an error message instead, so build out the headers
|
44
|
+
# and return the parcel.
|
45
|
+
error_headers = uuidable.create_uuids parcel[:headers]
|
46
|
+
error_headers[:kind] = 'serf/events/caught_error'
|
47
|
+
return parcel_builder.build error_headers, error_message
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'ice_nine'
|
2
|
+
|
3
|
+
require 'serf/util/options_extraction'
|
4
|
+
|
5
|
+
module Serf
|
6
|
+
module Middleware
|
7
|
+
|
8
|
+
##
|
9
|
+
# Middleware to add uuids to the headers of the parcel hash.
|
10
|
+
#
|
11
|
+
class ParcelFreezer
|
12
|
+
include Serf::Util::OptionsExtraction
|
13
|
+
|
14
|
+
attr_reader :app
|
15
|
+
attr_reader :freezer
|
16
|
+
|
17
|
+
##
|
18
|
+
# @param app the app
|
19
|
+
#
|
20
|
+
def initialize(app, *args)
|
21
|
+
extract_options! args
|
22
|
+
@app = app
|
23
|
+
@freezer = opts :freezer, IceNine
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Chains the call, but deep freezes the parcel.
|
28
|
+
def call(parcel)
|
29
|
+
freezer.deep_freeze parcel
|
30
|
+
app.call parcel
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
|
3
|
+
require 'serf/util/options_extraction'
|
4
|
+
|
5
|
+
module Serf
|
6
|
+
module Middleware
|
7
|
+
|
8
|
+
##
|
9
|
+
# Middleware to add uuids to the headers of the parcel hash.
|
10
|
+
#
|
11
|
+
class ParcelMasher
|
12
|
+
include Serf::Util::OptionsExtraction
|
13
|
+
|
14
|
+
attr_reader :app
|
15
|
+
attr_reader :masher_class
|
16
|
+
|
17
|
+
##
|
18
|
+
# @param app the app
|
19
|
+
#
|
20
|
+
def initialize(app, *args)
|
21
|
+
extract_options! args
|
22
|
+
@app = app
|
23
|
+
@masher_class = opts :masher_class, Hashie::Mash
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Coerces the parcel into a Hashie::Mash, makes sure that
|
28
|
+
# the headers and message are set, and then passes it along the chain.
|
29
|
+
def call(parcel)
|
30
|
+
mashed_parcel = masher_class.new parcel
|
31
|
+
mashed_parcel[:headers] ||= {}
|
32
|
+
mashed_parcel[:message] ||= {}
|
33
|
+
app.call mashed_parcel
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'serf/util/options_extraction'
|
2
|
+
|
3
|
+
module Serf
|
4
|
+
module Middleware
|
5
|
+
|
6
|
+
class PolicyChecker
|
7
|
+
include Serf::Util::OptionsExtraction
|
8
|
+
|
9
|
+
attr_reader :app
|
10
|
+
attr_reader :policy_chain
|
11
|
+
|
12
|
+
def initialize(app, *args)
|
13
|
+
extract_options! args
|
14
|
+
@app = app
|
15
|
+
@policy_chain = opts :policy_chain, []
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Iterates the policy chain and does a check for each policy.
|
20
|
+
# Assumes that policies will raise errors on any policy failure.
|
21
|
+
def call(parcel)
|
22
|
+
policy_chain.each do |policy|
|
23
|
+
policy.check! parcel
|
24
|
+
end
|
25
|
+
app.call parcel
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -1,36 +1,38 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
|
3
|
+
require 'serf/util/options_extraction'
|
1
4
|
require 'serf/util/uuidable'
|
2
5
|
|
3
6
|
module Serf
|
4
7
|
module Middleware
|
5
8
|
|
6
9
|
##
|
7
|
-
# Middleware to add
|
8
|
-
# of the env hash. But it won't overwrite the uuid field
|
9
|
-
# if the incoming request already has it.
|
10
|
+
# Middleware to add uuids to the headers of the parcel hash.
|
10
11
|
#
|
11
12
|
class UuidTagger
|
12
13
|
include Serf::Util::OptionsExtraction
|
13
14
|
|
15
|
+
attr_reader :app
|
14
16
|
attr_reader :uuidable
|
15
17
|
|
16
18
|
##
|
17
19
|
# @param app the app
|
18
|
-
# @options opts [String] :field the ENV field to set with a UUID.
|
19
20
|
#
|
20
21
|
def initialize(app, *args)
|
21
22
|
extract_options! args
|
22
23
|
@app = app
|
23
|
-
@uuidable = opts
|
24
|
+
@uuidable = opts(:uuidable) { Serf::Util::Uuidable.new }
|
24
25
|
end
|
25
26
|
|
26
|
-
def call(
|
27
|
-
|
28
|
-
|
27
|
+
def call(parcel)
|
28
|
+
# Makes sure our parcel has headers
|
29
|
+
parcel[:headers] ||= {}
|
29
30
|
|
30
|
-
|
31
|
-
|
31
|
+
# Tag headers with a UUID unless it already has one
|
32
|
+
parcel[:headers][:uuid] ||= uuidable.create_coded_uuid
|
32
33
|
|
33
|
-
|
34
|
+
# Pass on the given parcel with newly annotated headers
|
35
|
+
app.call parcel
|
34
36
|
end
|
35
37
|
|
36
38
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
|
3
|
+
require 'serf/util/options_extraction'
|
4
|
+
|
5
|
+
module Serf
|
6
|
+
|
7
|
+
##
|
8
|
+
# Builds Parcels as Hashie::Mash objects with headers and messages.
|
9
|
+
#
|
10
|
+
class ParcelBuilder
|
11
|
+
include Serf::Util::OptionsExtraction
|
12
|
+
|
13
|
+
attr_reader :mash_class
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
extract_options! args
|
17
|
+
|
18
|
+
@mash_class = opts :mash_class, Hashie::Mash
|
19
|
+
end
|
20
|
+
|
21
|
+
def build(headers=nil, message=nil)
|
22
|
+
# We want to make sure that our headers and message are Mashes.
|
23
|
+
headers = mash_class.new(headers) unless headers.kind_of? mash_class
|
24
|
+
message = mash_class.new(message) unless message.kind_of? mash_class
|
25
|
+
mash_class.new headers: headers, message: message
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/lib/serf/serfer.rb
CHANGED
@@ -1,87 +1,48 @@
|
|
1
1
|
require 'hashie'
|
2
2
|
|
3
|
-
require 'serf/
|
4
|
-
require 'serf/
|
5
|
-
require 'serf/util/
|
6
|
-
require 'serf/util/null_object'
|
3
|
+
require 'serf/parcel_builder'
|
4
|
+
require 'serf/util/options_extraction'
|
5
|
+
require 'serf/util/uuidable'
|
7
6
|
|
8
7
|
module Serf
|
9
8
|
|
10
9
|
##
|
11
|
-
# Class to drive the
|
12
|
-
#
|
10
|
+
# Class to drive the Interactor execution.
|
11
|
+
#
|
13
12
|
class Serfer
|
14
|
-
include Serf::Util::
|
13
|
+
include Serf::Util::OptionsExtraction
|
15
14
|
|
16
|
-
attr_reader :
|
17
|
-
attr_reader :
|
18
|
-
attr_reader :
|
19
|
-
attr_reader :logger
|
15
|
+
attr_reader :interactor
|
16
|
+
attr_reader :parcel_builder
|
17
|
+
attr_reader :uuidable
|
20
18
|
|
21
|
-
def initialize(*args)
|
19
|
+
def initialize(interactor, *args)
|
22
20
|
extract_options! args
|
23
21
|
|
24
|
-
|
25
|
-
@
|
26
|
-
|
27
|
-
|
22
|
+
# How to and when to handle requests
|
23
|
+
@interactor = interactor
|
24
|
+
|
25
|
+
# Tunable knobs
|
26
|
+
@parcel_builder = opts(:parcel_builder) { Serf::ParcelBuilder.new }
|
27
|
+
@uuidable = opts(:uuidable) { Serf::Util::Uuidable.new }
|
28
28
|
end
|
29
29
|
|
30
30
|
##
|
31
|
-
# Rack-like call to run
|
31
|
+
# Rack-like call to run the Interactor's use-case.
|
32
32
|
#
|
33
|
-
def call(
|
34
|
-
|
35
|
-
|
36
|
-
# We normalize by making the request a Hashie Mash
|
37
|
-
message = Hashie::Mash.new env.message
|
38
|
-
context = Hashie::Mash.new env.context
|
39
|
-
|
40
|
-
# Resolve the routes that we want to run
|
41
|
-
routes = route_set.resolve message, context
|
42
|
-
|
43
|
-
# We raise an error if no routes were found.
|
44
|
-
raise Serf::Errors::NotFound unless routes.size > 0
|
33
|
+
def call(parcel)
|
34
|
+
headers = parcel[:headers]
|
35
|
+
message = parcel[:message]
|
45
36
|
|
46
|
-
#
|
47
|
-
|
48
|
-
# 1. Check request+context with the policies (RAISE)
|
49
|
-
# 2. Execute command (RETURNS Hash)
|
50
|
-
ok, res = with_error_handling(
|
51
|
-
message: message,
|
52
|
-
options: context) do
|
53
|
-
route.check_policies! message, context
|
54
|
-
route.execute! message, context
|
55
|
-
end
|
56
|
-
# Return the run_results as result of this block.
|
57
|
-
res
|
58
|
-
}.flatten.select { |r| r }
|
59
|
-
push_results results, context
|
60
|
-
return results
|
61
|
-
rescue => e
|
62
|
-
e.extend(Serf::Error)
|
63
|
-
raise e
|
64
|
-
end
|
65
|
-
|
66
|
-
def self.build(*args, &block)
|
67
|
-
new *args, &block
|
68
|
-
end
|
37
|
+
# 1. Execute interactor
|
38
|
+
response_message, response_kind = interactor.call message
|
69
39
|
|
70
|
-
|
40
|
+
# 2. Create the response headers
|
41
|
+
response_headers = uuidable.create_uuids headers
|
42
|
+
response_headers[:kind] = response_kind
|
71
43
|
|
72
|
-
|
73
|
-
|
74
|
-
# Any error in pushing individual messages will result in
|
75
|
-
# a log event and an error channel event.
|
76
|
-
def push_results(results, context)
|
77
|
-
results.each do |result|
|
78
|
-
with_error_handling(result) do
|
79
|
-
response_channel.push(
|
80
|
-
message: result,
|
81
|
-
context: context)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
return nil
|
44
|
+
# 3. Return the response headers and message as a parcel
|
45
|
+
return parcel_builder.build response_headers, response_message
|
85
46
|
end
|
86
47
|
|
87
48
|
end
|
@@ -1,7 +1,3 @@
|
|
1
|
-
require 'active_support/core_ext/string/inflections'
|
2
|
-
|
3
|
-
require 'serf/util/null_object'
|
4
|
-
require 'serf/util/options_extraction'
|
5
1
|
require 'serf/util/protected_call'
|
6
2
|
|
7
3
|
module Serf
|
@@ -9,53 +5,34 @@ module Util
|
|
9
5
|
|
10
6
|
##
|
11
7
|
# Helper module to rescues exceptions from executing blocks of
|
12
|
-
# code, and then
|
8
|
+
# code, and then converts the exception to an "Error Message".
|
13
9
|
#
|
14
|
-
# Including classes may have the following instance variables
|
15
|
-
# to override the default values:
|
16
|
-
# * @logger - ::Serf::Util::NullObject.new
|
17
|
-
# * @error_channel - ::Serf::Util::NullObject.new
|
18
10
|
module ErrorHandling
|
19
|
-
include Serf::Util::OptionsExtraction
|
20
11
|
include Serf::Util::ProtectedCall
|
21
12
|
|
22
13
|
##
|
23
14
|
# A block wrapper to handle errors when executing a block.
|
24
15
|
#
|
25
|
-
def with_error_handling(
|
26
|
-
|
27
|
-
return
|
16
|
+
def with_error_handling(*args, &block)
|
17
|
+
results, err = pcall *args, &block
|
18
|
+
return results, handle_error(err)
|
28
19
|
end
|
29
20
|
|
30
21
|
##
|
31
22
|
# Including classes may override this method to do alternate error
|
32
|
-
# handling. By default, this method will create a new
|
33
|
-
# event and publish it to the error channel. This method will also
|
34
|
-
# log the exception itself to the logger.
|
23
|
+
# handling. By default, this method will create a new error event message.
|
35
24
|
#
|
36
|
-
def handle_error(e
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
error: e.class.to_s
|
25
|
+
def handle_error(e)
|
26
|
+
# no error was passed, so do nothing.
|
27
|
+
return nil unless e
|
28
|
+
|
29
|
+
# Return a simple error event message
|
30
|
+
return {
|
31
|
+
error: e.class.to_s,
|
43
32
|
message: e.message,
|
33
|
+
process_env: ENV.to_hash,
|
44
34
|
backtrace: e.backtrace.join("\n")
|
45
35
|
}
|
46
|
-
|
47
|
-
# log the error to our logger
|
48
|
-
logger.error e
|
49
|
-
|
50
|
-
# log the error event to our error channel.
|
51
|
-
begin
|
52
|
-
error_channel.push error_event
|
53
|
-
rescue => e1
|
54
|
-
logger.error e1
|
55
|
-
end
|
56
|
-
|
57
|
-
# We're done, so just return this error.
|
58
|
-
return error_event
|
59
36
|
end
|
60
37
|
|
61
38
|
end
|
@@ -24,9 +24,9 @@ module Util
|
|
24
24
|
# @return boolean success and the block's (or caught exception) results.
|
25
25
|
#
|
26
26
|
def pcall(*args)
|
27
|
-
return
|
27
|
+
return yield(*args), nil
|
28
28
|
rescue => e
|
29
|
-
return
|
29
|
+
return nil, e
|
30
30
|
end
|
31
31
|
alias_method :protected_call, :pcall
|
32
32
|
|