serf 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +10 -4
- data/Gemfile.lock +27 -17
- data/README.md +317 -120
- data/docs/thread_pools.txt +16 -0
- data/lib/serf/builder.rb +126 -162
- data/lib/serf/command.rb +113 -0
- data/lib/serf/message.rb +16 -2
- data/lib/serf/messages/caught_exception_event.rb +10 -7
- data/lib/serf/routing/endpoint.rb +49 -0
- data/lib/serf/routing/registry.rb +66 -0
- data/lib/serf/runners/direct.rb +52 -0
- data/lib/serf/runners/event_machine.rb +71 -0
- data/lib/serf/runners/girl_friday.rb +73 -0
- data/lib/serf/runners/helper.rb +23 -0
- data/lib/serf/serfer.rb +112 -25
- data/lib/serf/util/{with_error_handling.rb → error_handling.rb} +23 -10
- data/lib/serf/util/options_extraction.rb +106 -0
- data/lib/serf/version.rb +2 -2
- data/serf.gemspec +31 -20
- metadata +60 -33
- data/lib/serf/runners/direct_runner.rb +0 -60
- data/lib/serf/runners/em_runner.rb +0 -62
- data/lib/serf/util/route_endpoint.rb +0 -37
- data/lib/serf/util/route_set.rb +0 -82
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-03-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement: &
|
16
|
+
requirement: &70285339872700 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 3.2.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70285339872700
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: i18n
|
27
|
-
requirement: &
|
27
|
+
requirement: &70285339872080 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 0.6.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70285339872080
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: uuidtools
|
38
|
-
requirement: &
|
38
|
+
requirement: &70285339871240 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,54 +43,54 @@ dependencies:
|
|
43
43
|
version: 2.1.2
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70285339871240
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rspec
|
49
|
-
requirement: &
|
49
|
+
requirement: &70285339870220 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 2.
|
54
|
+
version: 2.8.0
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70285339870220
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: yard
|
60
|
-
requirement: &
|
60
|
+
requirement: &70285339869440 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
64
64
|
- !ruby/object:Gem::Version
|
65
|
-
version: 0.
|
65
|
+
version: 0.7.5
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70285339869440
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: bundler
|
71
|
-
requirement: &
|
71
|
+
requirement: &70285339868840 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ~>
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version: 1.0.
|
76
|
+
version: 1.0.22
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70285339868840
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: jeweler
|
82
|
-
requirement: &
|
82
|
+
requirement: &70285339868260 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ~>
|
86
86
|
- !ruby/object:Gem::Version
|
87
|
-
version: 1.
|
87
|
+
version: 1.8.3
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70285339868260
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: simplecov
|
93
|
-
requirement: &
|
93
|
+
requirement: &70285339867680 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,21 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70285339867680
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: log4r
|
104
|
+
requirement: &70285339866960 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.1.10
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *70285339866960
|
102
113
|
- !ruby/object:Gem::Dependency
|
103
114
|
name: msgpack
|
104
|
-
requirement: &
|
115
|
+
requirement: &70285339866280 !ruby/object:Gem::Requirement
|
105
116
|
none: false
|
106
117
|
requirements:
|
107
118
|
- - ! '>='
|
@@ -109,10 +120,10 @@ dependencies:
|
|
109
120
|
version: 0.4.6
|
110
121
|
type: :development
|
111
122
|
prerelease: false
|
112
|
-
version_requirements: *
|
123
|
+
version_requirements: *70285339866280
|
113
124
|
- !ruby/object:Gem::Dependency
|
114
125
|
name: eventmachine
|
115
|
-
requirement: &
|
126
|
+
requirement: &70285339914940 !ruby/object:Gem::Requirement
|
116
127
|
none: false
|
117
128
|
requirements:
|
118
129
|
- - ! '>='
|
@@ -120,7 +131,18 @@ dependencies:
|
|
120
131
|
version: 0.12.10
|
121
132
|
type: :development
|
122
133
|
prerelease: false
|
123
|
-
version_requirements: *
|
134
|
+
version_requirements: *70285339914940
|
135
|
+
- !ruby/object:Gem::Dependency
|
136
|
+
name: girl_friday
|
137
|
+
requirement: &70285339914320 !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ~>
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: 0.9.7
|
143
|
+
type: :development
|
144
|
+
prerelease: false
|
145
|
+
version_requirements: *70285339914320
|
124
146
|
description: Event-Driven SOA with CQRS
|
125
147
|
email: benjaminlyu@gmail.com
|
126
148
|
executables: []
|
@@ -137,22 +159,27 @@ files:
|
|
137
159
|
- NOTICE.txt
|
138
160
|
- README.md
|
139
161
|
- Rakefile
|
162
|
+
- docs/thread_pools.txt
|
140
163
|
- lib/serf.rb
|
141
164
|
- lib/serf/builder.rb
|
165
|
+
- lib/serf/command.rb
|
142
166
|
- lib/serf/error.rb
|
143
167
|
- lib/serf/message.rb
|
144
168
|
- lib/serf/messages/caught_exception_event.rb
|
145
169
|
- lib/serf/messages/message_accepted_event.rb
|
146
170
|
- lib/serf/middleware/uuid_tagger.rb
|
147
|
-
- lib/serf/
|
148
|
-
- lib/serf/
|
171
|
+
- lib/serf/routing/endpoint.rb
|
172
|
+
- lib/serf/routing/registry.rb
|
173
|
+
- lib/serf/runners/direct.rb
|
174
|
+
- lib/serf/runners/event_machine.rb
|
175
|
+
- lib/serf/runners/girl_friday.rb
|
176
|
+
- lib/serf/runners/helper.rb
|
149
177
|
- lib/serf/serfer.rb
|
178
|
+
- lib/serf/util/error_handling.rb
|
150
179
|
- lib/serf/util/null_object.rb
|
180
|
+
- lib/serf/util/options_extraction.rb
|
151
181
|
- lib/serf/util/regexp_matcher.rb
|
152
|
-
- lib/serf/util/route_endpoint.rb
|
153
|
-
- lib/serf/util/route_set.rb
|
154
182
|
- lib/serf/util/uuidable.rb
|
155
|
-
- lib/serf/util/with_error_handling.rb
|
156
183
|
- lib/serf/version.rb
|
157
184
|
- serf.gemspec
|
158
185
|
- spec/serf_spec.rb
|
@@ -172,7 +199,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
172
199
|
version: '0'
|
173
200
|
segments:
|
174
201
|
- 0
|
175
|
-
hash:
|
202
|
+
hash: 314755585934468655
|
176
203
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
177
204
|
none: false
|
178
205
|
requirements:
|
@@ -181,7 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
181
208
|
version: '0'
|
182
209
|
requirements: []
|
183
210
|
rubyforge_project:
|
184
|
-
rubygems_version: 1.8.
|
211
|
+
rubygems_version: 1.8.17
|
185
212
|
signing_key:
|
186
213
|
specification_version: 3
|
187
214
|
summary: Event-Driven SOA with CQRS
|
@@ -1,60 +0,0 @@
|
|
1
|
-
require 'serf/util/with_error_handling'
|
2
|
-
|
3
|
-
module Serf
|
4
|
-
module Runners
|
5
|
-
|
6
|
-
##
|
7
|
-
# Direct runner drives the execution of a handler for given messages.
|
8
|
-
# This class deals with error handling and publishing handler results
|
9
|
-
# to proper error or results channels.
|
10
|
-
#
|
11
|
-
class DirectRunner
|
12
|
-
include ::Serf::Util::WithErrorHandling
|
13
|
-
|
14
|
-
def initialize(options={})
|
15
|
-
# Mandatory, we want both results and error channels.
|
16
|
-
@results_channel = options.fetch(:results_channel)
|
17
|
-
@error_channel = options.fetch(:error_channel)
|
18
|
-
|
19
|
-
# Optional overrides for error handling
|
20
|
-
@error_event_class = options[:error_event_class]
|
21
|
-
@logger = options[:logger]
|
22
|
-
end
|
23
|
-
|
24
|
-
def run(endpoints, env)
|
25
|
-
results = []
|
26
|
-
endpoints.each do |ep|
|
27
|
-
run_results = with_error_handling(env) do
|
28
|
-
params = ep.message_parser ? ep.message_parser.parse(env) : env
|
29
|
-
ep.handler.send(ep.action, params)
|
30
|
-
end
|
31
|
-
results.concat Array(run_results)
|
32
|
-
publish_results run_results
|
33
|
-
end
|
34
|
-
return results
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.build(options={})
|
38
|
-
self.new options
|
39
|
-
end
|
40
|
-
|
41
|
-
protected
|
42
|
-
|
43
|
-
##
|
44
|
-
# Loop over the results and publish them to the results channel.
|
45
|
-
# Any error in publishing individual messages will result in
|
46
|
-
# a log event and an error channel event.
|
47
|
-
def publish_results(results)
|
48
|
-
results = Array(results)
|
49
|
-
results.each do |message|
|
50
|
-
with_error_handling(message) do
|
51
|
-
@results_channel.publish message
|
52
|
-
end
|
53
|
-
end
|
54
|
-
return nil
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
require 'eventmachine'
|
2
|
-
|
3
|
-
require 'serf/messages/message_accepted_event'
|
4
|
-
require 'serf/runners/direct_runner'
|
5
|
-
|
6
|
-
module Serf
|
7
|
-
module Runners
|
8
|
-
|
9
|
-
##
|
10
|
-
# This runner simply wraps another runner to execute in the
|
11
|
-
# EventMachine deferred threadpool.
|
12
|
-
#
|
13
|
-
# NOTE: Because the Serfer class validates messages before
|
14
|
-
# sending them to runners (and handlers), this class simply
|
15
|
-
# responds to the calling client with an 'MessageAcceptedEvent'
|
16
|
-
# to signal that the message will be processed later.
|
17
|
-
#
|
18
|
-
# Errors caught here will simply be logged. This is because
|
19
|
-
# the wrapped runner *MUST* handle its own errors. If an error
|
20
|
-
# should propagate up here, then it was most likely an error
|
21
|
-
# that occurred in a rescue block... we don't want to complicate
|
22
|
-
# any extra publishing to error channels because that may have
|
23
|
-
# been the cause of the error.
|
24
|
-
#
|
25
|
-
class EmRunner
|
26
|
-
|
27
|
-
def initialize(options={})
|
28
|
-
# Manditory: Need a runner because EmRunner is just a wrapper.
|
29
|
-
@runner = options.fetch(:runner)
|
30
|
-
|
31
|
-
@mae_class = options.fetch(:message_accepted_event_class) {
|
32
|
-
::Serf::Messages::MessageAcceptedEvent
|
33
|
-
}
|
34
|
-
@evm = options.fetch(:event_machine) { ::EventMachine }
|
35
|
-
@logger = options.fetch(:logger) { ::Serf::Util::NullObject.new }
|
36
|
-
end
|
37
|
-
|
38
|
-
def run(endpoints, env)
|
39
|
-
endpoints = endpoints.dup
|
40
|
-
env = env.dup
|
41
|
-
@evm.defer(proc do
|
42
|
-
begin
|
43
|
-
@runner.run endpoints, env
|
44
|
-
rescue => e
|
45
|
-
@logger.error "#{e.inspect}\n\n#{e.backtrace.join("\n")}"
|
46
|
-
end
|
47
|
-
end)
|
48
|
-
return @mae_class.new message: env
|
49
|
-
end
|
50
|
-
|
51
|
-
def self.build(options={})
|
52
|
-
options[:runner] = options.fetch(:runner) {
|
53
|
-
factory = options[:runner_factory] || ::Serf::Runners::DirectRunner
|
54
|
-
factory.build options
|
55
|
-
}
|
56
|
-
self.new options
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
|
61
|
-
end
|
62
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
module Serf
|
2
|
-
module Util
|
3
|
-
|
4
|
-
##
|
5
|
-
# A simple class to represent route endpoints. RouteSets
|
6
|
-
# store a list of endpoints per matcher, and Runners use endpoints
|
7
|
-
# to then execute the handlers.
|
8
|
-
#
|
9
|
-
class RouteEndpoint
|
10
|
-
# Actual handler object that defines the action method.
|
11
|
-
attr_accessor :handler
|
12
|
-
# The method to call.
|
13
|
-
attr_accessor :action
|
14
|
-
# A parser that turns the message ENV hash into a Message object
|
15
|
-
# that the handler#action uses.
|
16
|
-
attr_accessor :message_parser
|
17
|
-
|
18
|
-
def initialize(options={})
|
19
|
-
# Mandatory parameters
|
20
|
-
@handler = options.fetch :handler
|
21
|
-
@action = options.fetch :action
|
22
|
-
|
23
|
-
# Optional parameters
|
24
|
-
@message_parser = options[:message_parser]
|
25
|
-
end
|
26
|
-
|
27
|
-
##
|
28
|
-
# Default factory method.
|
29
|
-
#
|
30
|
-
def self.build(options={})
|
31
|
-
return self.new options
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
37
|
-
end
|
data/lib/serf/util/route_set.rb
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
require 'serf/util/route_endpoint'
|
2
|
-
require 'serf/util/regexp_matcher'
|
3
|
-
|
4
|
-
module Serf
|
5
|
-
module Util
|
6
|
-
|
7
|
-
##
|
8
|
-
# RouteSets hold routing information for ENV hashes to matched endpoints.
|
9
|
-
#
|
10
|
-
class RouteSet
|
11
|
-
|
12
|
-
def initialize(options={})
|
13
|
-
@routes = {}
|
14
|
-
@matchers = []
|
15
|
-
@regexp_matcher_factory = options.fetch(:regexp_matcher_factory) {
|
16
|
-
::Serf::Util::RegexpMatcher
|
17
|
-
}
|
18
|
-
@route_endpoint_factory = options.fetch(:route_endpoint_factory) {
|
19
|
-
::Serf::Util::RouteEndpoint
|
20
|
-
}
|
21
|
-
end
|
22
|
-
|
23
|
-
##
|
24
|
-
# Connects a matcher (String or an Object implementing ===) to an endpoint.
|
25
|
-
#
|
26
|
-
# @option opts [Obj, String] :matcher Matches ENV Hashes to endpoints.
|
27
|
-
# Note that String and Regexp values are set up to match the
|
28
|
-
# :kind key from ENV Hashes.
|
29
|
-
# @option opts [Obj] :handler Receiver of the action.
|
30
|
-
# @option opts [Symbol, String] :action Method to call on handler.
|
31
|
-
# @option opts [#parse] :message_parser Translates ENV Hash to Message Obj.
|
32
|
-
#
|
33
|
-
def add_route(options={})
|
34
|
-
# We create our endpoint representation.
|
35
|
-
endpoint = @route_endpoint_factory.build(
|
36
|
-
handler: options.fetch(:handler),
|
37
|
-
action: options.fetch(:action),
|
38
|
-
message_parser: options[:message_parser])
|
39
|
-
|
40
|
-
# Maybe we have an non-String matcher. Handle the Regexp case.
|
41
|
-
# We only keep track of matchers if it isn't a string because
|
42
|
-
# string matchers are just pulled out of routes by key lookup.
|
43
|
-
matcher = options.fetch :matcher
|
44
|
-
matcher = @regexp_matcher_factory.build matcher if matcher.kind_of? Regexp
|
45
|
-
@matchers << matcher unless matcher.is_a? String
|
46
|
-
|
47
|
-
# We add the route (matcher+endpoint) into our routes
|
48
|
-
@routes[matcher] ||= []
|
49
|
-
@routes[matcher] << endpoint
|
50
|
-
end
|
51
|
-
|
52
|
-
##
|
53
|
-
# @param [Hash] env The input message environment to match for routes.
|
54
|
-
# @return [Array] List of endpoints that matched.
|
55
|
-
#
|
56
|
-
def match_routes(env={})
|
57
|
-
kind = env[:kind]
|
58
|
-
routes = []
|
59
|
-
routes.concat Array(@routes[kind])
|
60
|
-
@matchers.each do |matcher|
|
61
|
-
routes.concat Array(@routes[matcher]) if matcher === env
|
62
|
-
end
|
63
|
-
return routes
|
64
|
-
end
|
65
|
-
|
66
|
-
##
|
67
|
-
# @return [Integer] Number of routes this RouteSet tracks.
|
68
|
-
#
|
69
|
-
def size
|
70
|
-
return @routes.size
|
71
|
-
end
|
72
|
-
|
73
|
-
##
|
74
|
-
# Default factory method.
|
75
|
-
#
|
76
|
-
def self.build(options={})
|
77
|
-
self.new options
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
end
|
82
|
-
end
|