serf 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -3
- data/Gemfile.lock +5 -3
- data/README.md +20 -87
- data/lib/serf/command.rb +11 -8
- data/lib/serf/middleware/uuid_tagger.rb +1 -2
- data/lib/serf/more/command_worker.rb +0 -6
- data/lib/serf/runners/event_machine.rb +4 -6
- data/lib/serf/runners/girl_friday.rb +4 -8
- data/lib/serf/util/error_handling.rb +5 -6
- data/lib/serf/util/mash_factory.rb +18 -0
- data/lib/serf/util/uuidable.rb +27 -2
- data/lib/serf/version.rb +1 -1
- data/schemas/caught_exception_event.json +21 -0
- data/schemas/message_accepted_event.json +14 -0
- data/serf.gemspec +17 -15
- metadata +44 -34
- data/lib/serf/message.rb +0 -56
- data/lib/serf/messages/caught_exception_event.rb +0 -49
- data/lib/serf/messages/message_accepted_event.rb +0 -38
- data/lib/serf/more/uuid_fields.rb +0 -29
data/Gemfile
CHANGED
@@ -6,6 +6,7 @@ source 'http://rubygems.org'
|
|
6
6
|
# Requirements for both clients and servers.
|
7
7
|
gem 'activesupport', '>= 3.2.0'
|
8
8
|
gem 'i18n', '>= 0.6.0' # For ActiveSupport
|
9
|
+
gem 'hashie', ">= 1.2.0"
|
9
10
|
# Used by Serf::Messages::*
|
10
11
|
gem 'uuidtools', '>= 2.1.2'
|
11
12
|
|
@@ -14,12 +15,12 @@ gem 'uuidtools', '>= 2.1.2'
|
|
14
15
|
group :development, :test do
|
15
16
|
gem "rspec", "~> 2.8.0"
|
16
17
|
gem "yard", "~> 0.7.5"
|
17
|
-
gem "bundler", "~> 1.
|
18
|
+
gem "bundler", "~> 1.1.3"
|
18
19
|
gem "jeweler", "~> 1.8.3"
|
19
20
|
gem 'simplecov', '>= 0'
|
20
21
|
|
21
22
|
# For our testing
|
22
|
-
gem 'log4r', '
|
23
|
+
gem 'log4r', '>= 1.1.10'
|
23
24
|
|
24
25
|
# Soft Dependencies
|
25
26
|
#gem 'log4r', '~> 1.1.9'
|
@@ -30,5 +31,5 @@ group :development, :test do
|
|
30
31
|
|
31
32
|
# EventMachine is now optional runner
|
32
33
|
gem 'eventmachine', '>= 0.12.10'
|
33
|
-
gem 'girl_friday', '
|
34
|
+
gem 'girl_friday', '>= 0.9.7'
|
34
35
|
end
|
data/Gemfile.lock
CHANGED
@@ -10,6 +10,7 @@ GEM
|
|
10
10
|
girl_friday (0.9.7)
|
11
11
|
connection_pool (~> 0.1.0)
|
12
12
|
git (1.2.5)
|
13
|
+
hashie (1.2.0)
|
13
14
|
i18n (0.6.0)
|
14
15
|
jeweler (1.8.3)
|
15
16
|
bundler (~> 1.0)
|
@@ -43,12 +44,13 @@ PLATFORMS
|
|
43
44
|
|
44
45
|
DEPENDENCIES
|
45
46
|
activesupport (>= 3.2.0)
|
46
|
-
bundler (~> 1.
|
47
|
+
bundler (~> 1.1.3)
|
47
48
|
eventmachine (>= 0.12.10)
|
48
|
-
girl_friday (
|
49
|
+
girl_friday (>= 0.9.7)
|
50
|
+
hashie (>= 1.2.0)
|
49
51
|
i18n (>= 0.6.0)
|
50
52
|
jeweler (~> 1.8.3)
|
51
|
-
log4r (
|
53
|
+
log4r (>= 1.1.10)
|
52
54
|
msgpack (>= 0.4.6)
|
53
55
|
rspec (~> 2.8.0)
|
54
56
|
simplecov
|
data/README.md
CHANGED
@@ -21,7 +21,7 @@ Messages are the representation of data, documents, etc that are
|
|
21
21
|
marshalled from client to service, which represents the business
|
22
22
|
level interaction of the service.
|
23
23
|
|
24
|
-
Messages may be
|
24
|
+
Messages may be command requests that a service must handle.
|
25
25
|
Messages may be events that a service emits.
|
26
26
|
Messages may be documents that represent state or business data.
|
27
27
|
|
@@ -59,54 +59,23 @@ Not implemented as yet:
|
|
59
59
|
Service Libraries
|
60
60
|
=================
|
61
61
|
|
62
|
-
1. Service Libraries SHOULD implement
|
63
|
-
|
64
|
-
a.
|
65
|
-
|
62
|
+
1. Service Libraries SHOULD implement messages as just hashes with
|
63
|
+
defined schemas (JSON Schema).
|
64
|
+
a. Required by all messages is the 'kind' field.
|
65
|
+
b. By default, Serf Commands will read in hashes and turn them into
|
66
|
+
more convenient Hashie::Mash objects.
|
66
67
|
2. Serialization of the messages SHOULD BE Json or MessagePack (I hate XML).
|
67
|
-
a.
|
68
|
+
a. Serf Builder will create Serf Apps that expect a HASH ENV as input
|
68
69
|
3. Handlers MUST implement the 'build' class method, which
|
69
70
|
MUST receive the ENV Hash as the first parameter, followed by supplemental
|
70
71
|
arguments as declared in the DSL.
|
71
72
|
4. Handler methods SHOULD return zero or more messages.
|
72
73
|
a. Raised errors are caught and pushed to error channels.
|
74
|
+
b. Returned messages MUST be Hash based objects for Serialization.
|
73
75
|
5. Handler methods SHOULD handle catch their business logic exceptions and
|
74
76
|
return them as specialized messages that can be forwarded down error channels.
|
75
77
|
Uncaught exceptions that are then caught by Serf are pushed as
|
76
|
-
generic
|
77
|
-
|
78
|
-
|
79
|
-
Serf::Message
|
80
|
-
-------------
|
81
|
-
|
82
|
-
Users of the Serf::Message module need to be aware of that:
|
83
|
-
|
84
|
-
1. Messages MUST implement the `#attributes` method to use the
|
85
|
-
default implementations of `to_msgpack`, `to_json`, and `to_hash`.
|
86
|
-
2. Messages MAY implement validation helpers (e.g. ActiveModel or
|
87
|
-
Virtus + Aequitas (DataMapper)). This is purely to be helpful for
|
88
|
-
receivers (Serf::Handlers) to validate the Messages before running
|
89
|
-
code against its data. The Serf infrastructure code does not
|
90
|
-
validate the Messages; it is the job of the handler code.
|
91
|
-
3. Messages MAY override `Message.parse` class method if they want
|
92
|
-
different parsing (Message object instantiation) than
|
93
|
-
`message_class.new *args`. This parse method is called in
|
94
|
-
Serf::Handler when the handler class has defined a Message class
|
95
|
-
to be used to deserialize the ENV for a handler action method.
|
96
|
-
3. Messages MAY override `Message#kind` instance method or `Message.kind`
|
97
|
-
class method to specify a message `kind` that is different than
|
98
|
-
the tableized name of the implementing ruby class.
|
99
|
-
4. Messages MAY override `Message#to_msgpack`, `Message#to_json`, or
|
100
|
-
`Message#to_hash` to get alternate serialization.
|
101
|
-
|
102
|
-
User that opt to roll their own Message class only need to be
|
103
|
-
aware that:
|
104
|
-
|
105
|
-
1. Message classes MUST implement `Message.parse(env={})` class method
|
106
|
-
if said message class is to be used as the target object representation
|
107
|
-
of a received message (from ENV hash).
|
108
|
-
a. Serf code makes this assumption when it finds an ENV
|
109
|
-
hash that is to be parsed into a message object.
|
78
|
+
generic CaughtExceptionEvents, and are harder to deal with.
|
110
79
|
|
111
80
|
|
112
81
|
Example With GirlFriday
|
@@ -118,7 +87,6 @@ Example With GirlFriday
|
|
118
87
|
|
119
88
|
require 'serf/builder'
|
120
89
|
require 'serf/command'
|
121
|
-
require 'serf/message'
|
122
90
|
require 'serf/middleware/uuid_tagger'
|
123
91
|
require 'serf/util/options_extraction'
|
124
92
|
|
@@ -151,38 +119,20 @@ Example With GirlFriday
|
|
151
119
|
end
|
152
120
|
end
|
153
121
|
|
154
|
-
# my_lib/
|
155
|
-
|
156
|
-
# ActiveModel or Aequitas/Virtus implements.
|
157
|
-
class MyMessage
|
158
|
-
include Serf::Util::OptionsExtraction
|
159
|
-
include Serf::Message
|
160
|
-
|
161
|
-
attr_accessor :data
|
162
|
-
|
163
|
-
def initialize(*args)
|
164
|
-
extract_options! args
|
165
|
-
self.data = opts :data
|
166
|
-
end
|
122
|
+
# my_lib/my_validator.rb
|
123
|
+
class MyValidator
|
167
124
|
|
168
|
-
def
|
169
|
-
|
125
|
+
def self.validate!(data)
|
126
|
+
raise 'Data is nil' if data[:data].nil?
|
170
127
|
end
|
171
128
|
|
172
|
-
def valid?
|
173
|
-
!data.nil?
|
174
|
-
end
|
175
|
-
|
176
|
-
def full_error_messages
|
177
|
-
'Data is blank' if data.nil?
|
178
|
-
end
|
179
129
|
end
|
180
130
|
|
181
131
|
# my_lib/my_overloaded_command.rb
|
182
132
|
class MyOverloadedCommand
|
183
133
|
include Serf::Command
|
184
134
|
|
185
|
-
self.
|
135
|
+
self.request_validator = MyValidator
|
186
136
|
|
187
137
|
def initialize(*args)
|
188
138
|
super
|
@@ -304,6 +254,7 @@ Example With GirlFriday
|
|
304
254
|
end
|
305
255
|
logger.info "End Tick #{Thread.current.object_id}"
|
306
256
|
|
257
|
+
|
307
258
|
Example With EventMachine
|
308
259
|
=========================
|
309
260
|
|
@@ -313,7 +264,6 @@ Example With EventMachine
|
|
313
264
|
|
314
265
|
require 'serf/builder'
|
315
266
|
require 'serf/command'
|
316
|
-
require 'serf/message'
|
317
267
|
require 'serf/middleware/uuid_tagger'
|
318
268
|
require 'serf/util/options_extraction'
|
319
269
|
|
@@ -347,37 +297,19 @@ Example With EventMachine
|
|
347
297
|
end
|
348
298
|
|
349
299
|
# my_lib/my_message.rb
|
350
|
-
|
351
|
-
# ActiveModel or Aequitas/Virtus implements.
|
352
|
-
class MyMessage
|
353
|
-
include Serf::Util::OptionsExtraction
|
354
|
-
include Serf::Message
|
300
|
+
class MyValidator
|
355
301
|
|
356
|
-
|
357
|
-
|
358
|
-
def initialize(*args)
|
359
|
-
extract_options! args
|
360
|
-
self.data = opts :data
|
361
|
-
end
|
362
|
-
|
363
|
-
def attributes
|
364
|
-
{ 'data' => data }
|
302
|
+
def self.validate!(data)
|
303
|
+
raise 'Data Missing Error' if data[:data].nil?
|
365
304
|
end
|
366
305
|
|
367
|
-
def valid?
|
368
|
-
!data.nil?
|
369
|
-
end
|
370
|
-
|
371
|
-
def full_error_messages
|
372
|
-
'Data is blank' if data.nil?
|
373
|
-
end
|
374
306
|
end
|
375
307
|
|
376
308
|
# my_lib/my_overloaded_command.rb
|
377
309
|
class MyOverloadedCommand
|
378
310
|
include Serf::Command
|
379
311
|
|
380
|
-
self.
|
312
|
+
self.request_validator = MyValidator
|
381
313
|
|
382
314
|
def initialize(*args)
|
383
315
|
super
|
@@ -506,6 +438,7 @@ Example With EventMachine
|
|
506
438
|
end
|
507
439
|
end
|
508
440
|
|
441
|
+
|
509
442
|
Contributing to serf
|
510
443
|
====================
|
511
444
|
|
data/lib/serf/command.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'active_support/concern'
|
2
2
|
require 'active_support/core_ext/class/attribute'
|
3
3
|
|
4
|
+
require 'serf/util/mash_factory'
|
4
5
|
require 'serf/util/options_extraction'
|
5
6
|
|
6
7
|
module Serf
|
@@ -14,6 +15,10 @@ module Serf
|
|
14
15
|
# # Set a default Message Parser for the class.
|
15
16
|
# self.request_factory = MySerfRequestMessage
|
16
17
|
#
|
18
|
+
# # Validate the request, like using JSON-Schema for hash
|
19
|
+
# # (or Hashie's Mash) requests.
|
20
|
+
# self.request_validator = MySerfRequestValidator
|
21
|
+
#
|
17
22
|
# def initialize(*args, &block)
|
18
23
|
# # Do some validation here, or extra parameter setting with the args
|
19
24
|
# end
|
@@ -37,6 +42,8 @@ module Serf
|
|
37
42
|
|
38
43
|
included do
|
39
44
|
class_attribute :request_factory
|
45
|
+
__send__ 'request_factory=', Serf::Util::MashFactory
|
46
|
+
class_attribute :request_validator
|
40
47
|
attr_reader :request
|
41
48
|
end
|
42
49
|
|
@@ -45,11 +52,7 @@ module Serf
|
|
45
52
|
end
|
46
53
|
|
47
54
|
def validate_request!
|
48
|
-
|
49
|
-
# request object isn't a hash.
|
50
|
-
unless request.is_a?(Hash) || request.valid?
|
51
|
-
raise ArgumentError, request.full_error_messages
|
52
|
-
end
|
55
|
+
request_validator.validate! request if request_validator
|
53
56
|
end
|
54
57
|
|
55
58
|
module ClassMethods
|
@@ -86,14 +89,14 @@ module Serf
|
|
86
89
|
# Set the request instance variable to whatever type of request we got.
|
87
90
|
obj.instance_variable_set :@request, request
|
88
91
|
|
92
|
+
# Finalize the object's construction with the rest of the args & block.
|
93
|
+
obj.__send__ :initialize, *args, &block
|
94
|
+
|
89
95
|
# Now validate that the request is ok.
|
90
96
|
# Implementing classes MAY override this method to do different
|
91
97
|
# kind of request validation.
|
92
98
|
obj.validate_request!
|
93
99
|
|
94
|
-
# Finalize the object's construction with the rest of the args & block.
|
95
|
-
obj.__send__ :initialize, *args, &block
|
96
|
-
|
97
100
|
return obj
|
98
101
|
end
|
99
102
|
|
@@ -9,7 +9,6 @@ module Middleware
|
|
9
9
|
# if the incoming request already has it.
|
10
10
|
#
|
11
11
|
class UuidTagger
|
12
|
-
include Serf::Util::Uuidable
|
13
12
|
|
14
13
|
##
|
15
14
|
# @param app the app
|
@@ -23,7 +22,7 @@ module Middleware
|
|
23
22
|
def call(env)
|
24
23
|
env = env.dup
|
25
24
|
unless env[@field.to_sym] || env[@field.to_s]
|
26
|
-
env[@field] = create_coded_uuid
|
25
|
+
env[@field] = Serf::Util::Uuidable.create_coded_uuid
|
27
26
|
end
|
28
27
|
@app.call env
|
29
28
|
end
|
@@ -39,12 +39,6 @@ module More
|
|
39
39
|
return results
|
40
40
|
end
|
41
41
|
|
42
|
-
# Overriding the Serf::Command validate_request! so it doesn't
|
43
|
-
# call #valid? on the request object. This is because the incoming
|
44
|
-
# request is another Command object itself.
|
45
|
-
def validate_request!
|
46
|
-
end
|
47
|
-
|
48
42
|
end
|
49
43
|
|
50
44
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'eventmachine'
|
2
2
|
|
3
|
-
require 'serf/messages/message_accepted_event'
|
4
3
|
require 'serf/runners/direct'
|
5
4
|
require 'serf/util/error_handling'
|
6
5
|
|
@@ -32,10 +31,6 @@ module Runners
|
|
32
31
|
# Manditory: Need a runner because this class is just a wrapper.
|
33
32
|
@runner = opts! :runner
|
34
33
|
|
35
|
-
@mae_class = opts(
|
36
|
-
:message_accepted_event_class,
|
37
|
-
::Serf::Messages::MessageAcceptedEvent)
|
38
|
-
|
39
34
|
@evm = opts :event_machine, ::EventMachine
|
40
35
|
@logger = opts :logger, ::Serf::Util::NullObject.new
|
41
36
|
end
|
@@ -54,7 +49,10 @@ module Runners
|
|
54
49
|
end
|
55
50
|
end)
|
56
51
|
end
|
57
|
-
return
|
52
|
+
return {
|
53
|
+
kind: 'serf/messages/message_accepted_event',
|
54
|
+
message: context
|
55
|
+
}
|
58
56
|
end
|
59
57
|
|
60
58
|
def self.build(options={})
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'girl_friday'
|
2
2
|
|
3
|
-
require 'serf/messages/message_accepted_event'
|
4
3
|
require 'serf/runners/helper'
|
5
4
|
require 'serf/util/error_handling'
|
6
5
|
|
@@ -30,12 +29,6 @@ module Runners
|
|
30
29
|
end
|
31
30
|
|
32
31
|
def call(handlers, context)
|
33
|
-
# Create our accepted event before we enqueue the handlers.
|
34
|
-
mae_class = opts(
|
35
|
-
:message_accepted_event_class,
|
36
|
-
::Serf::Messages::MessageAcceptedEvent)
|
37
|
-
event = mae_class.new message: context
|
38
|
-
|
39
32
|
# Push each handler into the queue along with a copy of the context.
|
40
33
|
handlers.each do |handler|
|
41
34
|
@queue.push(
|
@@ -45,7 +38,10 @@ module Runners
|
|
45
38
|
|
46
39
|
# We got here, we succeeded pushing all the works.
|
47
40
|
# Now we return our accepted event.
|
48
|
-
return
|
41
|
+
return {
|
42
|
+
kind: 'serf/messages/message_accepted_event',
|
43
|
+
message: context
|
44
|
+
}
|
49
45
|
end
|
50
46
|
|
51
47
|
##
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'active_support/core_ext/string/inflections'
|
2
2
|
|
3
|
-
require 'serf/messages/caught_exception_event'
|
4
3
|
require 'serf/util/null_object'
|
5
4
|
require 'serf/util/options_extraction'
|
6
5
|
require 'serf/util/protected_call'
|
@@ -14,7 +13,6 @@ module Util
|
|
14
13
|
#
|
15
14
|
# Including classes may have the following instance variables
|
16
15
|
# to override the default values:
|
17
|
-
# * @error_event_class - ::Serf::Messages::CaughtExceptionEvent
|
18
16
|
# * @logger - ::Serf::Util::NullObject.new
|
19
17
|
# * @error_channel - ::Serf::Util::NullObject.new
|
20
18
|
module ErrorHandling
|
@@ -40,14 +38,15 @@ module Util
|
|
40
38
|
# log the exception itself to the logger.
|
41
39
|
#
|
42
40
|
def handle_error(e, context=nil)
|
43
|
-
eec = opts :error_event_class, ::Serf::Messages::CaughtExceptionEvent
|
44
41
|
logger = opts :logger, ::Serf::Util::NullObject.new
|
45
42
|
error_channel = opts :error_channel, ::Serf::Util::NullObject.new
|
46
|
-
error_event =
|
43
|
+
error_event = {
|
44
|
+
kind: 'serf/messages/caught_exception_event',
|
47
45
|
context: context,
|
48
|
-
error: e.class.to_s.
|
46
|
+
error: e.class.to_s.underscore,
|
49
47
|
message: e.message,
|
50
|
-
backtrace: e.backtrace.join("\n")
|
48
|
+
backtrace: e.backtrace.join("\n")
|
49
|
+
}
|
51
50
|
|
52
51
|
# log the error to our logger
|
53
52
|
logger.error e
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
|
3
|
+
module Serf
|
4
|
+
module Util
|
5
|
+
|
6
|
+
##
|
7
|
+
# A Request Factory that just coerces a REQUEST ENV hash message
|
8
|
+
# into a Hashie::Mash object for convenience key/value access.
|
9
|
+
#
|
10
|
+
module MashFactory
|
11
|
+
|
12
|
+
def self.build(message)
|
13
|
+
Hashie::Mash.new message
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
data/lib/serf/util/uuidable.rb
CHANGED
@@ -17,7 +17,7 @@ module Util
|
|
17
17
|
#
|
18
18
|
# NOTE: UUIDTools TimeStamp code creates a UTC based timestamp UUID.
|
19
19
|
#
|
20
|
-
def create_coded_uuid
|
20
|
+
def self.create_coded_uuid
|
21
21
|
# All raw UUIDs are 16 bytes long. Base64 lengthens the string to
|
22
22
|
# 24 bytes long. We chomp off the last two equal signs '==' to
|
23
23
|
# trim the string length to 22 bytes. This gives us an overhead
|
@@ -30,10 +30,35 @@ module Util
|
|
30
30
|
##
|
31
31
|
# @param coded_uuid a coded uuid to parse.
|
32
32
|
#
|
33
|
-
def parse_coded_uuid(coded_uuid)
|
33
|
+
def self.parse_coded_uuid(coded_uuid)
|
34
34
|
UUIDTools::UUID.parse_raw Base64.urlsafe_decode64("#{coded_uuid}==")
|
35
35
|
end
|
36
36
|
|
37
|
+
##
|
38
|
+
# Create a new set of uuids.
|
39
|
+
#
|
40
|
+
def self.create_uuids(parent={})
|
41
|
+
{
|
42
|
+
uuid: create_coded_uuid,
|
43
|
+
parent_uuid: parent['uuid'],
|
44
|
+
origin_uuid: (
|
45
|
+
parent[:origin_uuid] ||
|
46
|
+
parent[:parent_uuid] ||
|
47
|
+
parent[:uuid])
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Set a message's UUIDs with new UUIDs based on the parent's UUIDs.
|
53
|
+
#
|
54
|
+
def self.annotate_with_uuids!(message, parent={})
|
55
|
+
uuids = self.create_uuids parent
|
56
|
+
message[:uuid] ||= uuids[:uuid]
|
57
|
+
message[:parent_uuid] ||= uuids[:parent_uuid]
|
58
|
+
message[:origin_uuid] ||= uuids[:origin_uuid]
|
59
|
+
return nil
|
60
|
+
end
|
61
|
+
|
37
62
|
end
|
38
63
|
|
39
64
|
end
|
data/lib/serf/version.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
{
|
2
|
+
"description": "Message Kind: serf/messages/caught_exception_event",
|
3
|
+
"type": "object",
|
4
|
+
"properties": {
|
5
|
+
"context": {
|
6
|
+
"type": "object"
|
7
|
+
},
|
8
|
+
"error": {
|
9
|
+
"type": "string"
|
10
|
+
},
|
11
|
+
"message": {
|
12
|
+
"type": "string"
|
13
|
+
},
|
14
|
+
"backtrace": {
|
15
|
+
"type": "string"
|
16
|
+
},
|
17
|
+
"uuid": {
|
18
|
+
"type": "string"
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
data/serf.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "serf"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.9.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Benjamin Yu"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-05-06"
|
13
13
|
s.description = "Event-Driven SOA with CQRS"
|
14
14
|
s.email = "benjaminlyu@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -30,12 +30,8 @@ Gem::Specification.new do |s|
|
|
30
30
|
"lib/serf/builder.rb",
|
31
31
|
"lib/serf/command.rb",
|
32
32
|
"lib/serf/error.rb",
|
33
|
-
"lib/serf/message.rb",
|
34
|
-
"lib/serf/messages/caught_exception_event.rb",
|
35
|
-
"lib/serf/messages/message_accepted_event.rb",
|
36
33
|
"lib/serf/middleware/uuid_tagger.rb",
|
37
34
|
"lib/serf/more/command_worker.rb",
|
38
|
-
"lib/serf/more/uuid_fields.rb",
|
39
35
|
"lib/serf/routing/endpoint.rb",
|
40
36
|
"lib/serf/routing/registry.rb",
|
41
37
|
"lib/serf/runners/direct.rb",
|
@@ -44,12 +40,15 @@ Gem::Specification.new do |s|
|
|
44
40
|
"lib/serf/runners/helper.rb",
|
45
41
|
"lib/serf/serfer.rb",
|
46
42
|
"lib/serf/util/error_handling.rb",
|
43
|
+
"lib/serf/util/mash_factory.rb",
|
47
44
|
"lib/serf/util/null_object.rb",
|
48
45
|
"lib/serf/util/options_extraction.rb",
|
49
46
|
"lib/serf/util/protected_call.rb",
|
50
47
|
"lib/serf/util/regexp_matcher.rb",
|
51
48
|
"lib/serf/util/uuidable.rb",
|
52
49
|
"lib/serf/version.rb",
|
50
|
+
"schemas/caught_exception_event.json",
|
51
|
+
"schemas/message_accepted_event.json",
|
53
52
|
"serf.gemspec",
|
54
53
|
"spec/serf_spec.rb",
|
55
54
|
"spec/spec_helper.rb"
|
@@ -66,43 +65,46 @@ Gem::Specification.new do |s|
|
|
66
65
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
67
66
|
s.add_runtime_dependency(%q<activesupport>, [">= 3.2.0"])
|
68
67
|
s.add_runtime_dependency(%q<i18n>, [">= 0.6.0"])
|
68
|
+
s.add_runtime_dependency(%q<hashie>, [">= 1.2.0"])
|
69
69
|
s.add_runtime_dependency(%q<uuidtools>, [">= 2.1.2"])
|
70
70
|
s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
|
71
71
|
s.add_development_dependency(%q<yard>, ["~> 0.7.5"])
|
72
|
-
s.add_development_dependency(%q<bundler>, ["~> 1.
|
72
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.1.3"])
|
73
73
|
s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
|
74
74
|
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
75
|
-
s.add_development_dependency(%q<log4r>, ["
|
75
|
+
s.add_development_dependency(%q<log4r>, [">= 1.1.10"])
|
76
76
|
s.add_development_dependency(%q<msgpack>, [">= 0.4.6"])
|
77
77
|
s.add_development_dependency(%q<eventmachine>, [">= 0.12.10"])
|
78
|
-
s.add_development_dependency(%q<girl_friday>, ["
|
78
|
+
s.add_development_dependency(%q<girl_friday>, [">= 0.9.7"])
|
79
79
|
else
|
80
80
|
s.add_dependency(%q<activesupport>, [">= 3.2.0"])
|
81
81
|
s.add_dependency(%q<i18n>, [">= 0.6.0"])
|
82
|
+
s.add_dependency(%q<hashie>, [">= 1.2.0"])
|
82
83
|
s.add_dependency(%q<uuidtools>, [">= 2.1.2"])
|
83
84
|
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
84
85
|
s.add_dependency(%q<yard>, ["~> 0.7.5"])
|
85
|
-
s.add_dependency(%q<bundler>, ["~> 1.
|
86
|
+
s.add_dependency(%q<bundler>, ["~> 1.1.3"])
|
86
87
|
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
87
88
|
s.add_dependency(%q<simplecov>, [">= 0"])
|
88
|
-
s.add_dependency(%q<log4r>, ["
|
89
|
+
s.add_dependency(%q<log4r>, [">= 1.1.10"])
|
89
90
|
s.add_dependency(%q<msgpack>, [">= 0.4.6"])
|
90
91
|
s.add_dependency(%q<eventmachine>, [">= 0.12.10"])
|
91
|
-
s.add_dependency(%q<girl_friday>, ["
|
92
|
+
s.add_dependency(%q<girl_friday>, [">= 0.9.7"])
|
92
93
|
end
|
93
94
|
else
|
94
95
|
s.add_dependency(%q<activesupport>, [">= 3.2.0"])
|
95
96
|
s.add_dependency(%q<i18n>, [">= 0.6.0"])
|
97
|
+
s.add_dependency(%q<hashie>, [">= 1.2.0"])
|
96
98
|
s.add_dependency(%q<uuidtools>, [">= 2.1.2"])
|
97
99
|
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
98
100
|
s.add_dependency(%q<yard>, ["~> 0.7.5"])
|
99
|
-
s.add_dependency(%q<bundler>, ["~> 1.
|
101
|
+
s.add_dependency(%q<bundler>, ["~> 1.1.3"])
|
100
102
|
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
101
103
|
s.add_dependency(%q<simplecov>, [">= 0"])
|
102
|
-
s.add_dependency(%q<log4r>, ["
|
104
|
+
s.add_dependency(%q<log4r>, [">= 1.1.10"])
|
103
105
|
s.add_dependency(%q<msgpack>, [">= 0.4.6"])
|
104
106
|
s.add_dependency(%q<eventmachine>, [">= 0.12.10"])
|
105
|
-
s.add_dependency(%q<girl_friday>, ["
|
107
|
+
s.add_dependency(%q<girl_friday>, [">= 0.9.7"])
|
106
108
|
end
|
107
109
|
end
|
108
110
|
|
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.9.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-05-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement: &
|
16
|
+
requirement: &70100670653360 !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: *70100670653360
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: i18n
|
27
|
-
requirement: &
|
27
|
+
requirement: &70100670652560 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,21 @@ dependencies:
|
|
32
32
|
version: 0.6.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70100670652560
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: hashie
|
38
|
+
requirement: &70100670651180 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.2.0
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70100670651180
|
36
47
|
- !ruby/object:Gem::Dependency
|
37
48
|
name: uuidtools
|
38
|
-
requirement: &
|
49
|
+
requirement: &70100670649260 !ruby/object:Gem::Requirement
|
39
50
|
none: false
|
40
51
|
requirements:
|
41
52
|
- - ! '>='
|
@@ -43,10 +54,10 @@ dependencies:
|
|
43
54
|
version: 2.1.2
|
44
55
|
type: :runtime
|
45
56
|
prerelease: false
|
46
|
-
version_requirements: *
|
57
|
+
version_requirements: *70100670649260
|
47
58
|
- !ruby/object:Gem::Dependency
|
48
59
|
name: rspec
|
49
|
-
requirement: &
|
60
|
+
requirement: &70100670647520 !ruby/object:Gem::Requirement
|
50
61
|
none: false
|
51
62
|
requirements:
|
52
63
|
- - ~>
|
@@ -54,10 +65,10 @@ dependencies:
|
|
54
65
|
version: 2.8.0
|
55
66
|
type: :development
|
56
67
|
prerelease: false
|
57
|
-
version_requirements: *
|
68
|
+
version_requirements: *70100670647520
|
58
69
|
- !ruby/object:Gem::Dependency
|
59
70
|
name: yard
|
60
|
-
requirement: &
|
71
|
+
requirement: &70100670646500 !ruby/object:Gem::Requirement
|
61
72
|
none: false
|
62
73
|
requirements:
|
63
74
|
- - ~>
|
@@ -65,21 +76,21 @@ dependencies:
|
|
65
76
|
version: 0.7.5
|
66
77
|
type: :development
|
67
78
|
prerelease: false
|
68
|
-
version_requirements: *
|
79
|
+
version_requirements: *70100670646500
|
69
80
|
- !ruby/object:Gem::Dependency
|
70
81
|
name: bundler
|
71
|
-
requirement: &
|
82
|
+
requirement: &70100670814180 !ruby/object:Gem::Requirement
|
72
83
|
none: false
|
73
84
|
requirements:
|
74
85
|
- - ~>
|
75
86
|
- !ruby/object:Gem::Version
|
76
|
-
version: 1.
|
87
|
+
version: 1.1.3
|
77
88
|
type: :development
|
78
89
|
prerelease: false
|
79
|
-
version_requirements: *
|
90
|
+
version_requirements: *70100670814180
|
80
91
|
- !ruby/object:Gem::Dependency
|
81
92
|
name: jeweler
|
82
|
-
requirement: &
|
93
|
+
requirement: &70100670813540 !ruby/object:Gem::Requirement
|
83
94
|
none: false
|
84
95
|
requirements:
|
85
96
|
- - ~>
|
@@ -87,10 +98,10 @@ dependencies:
|
|
87
98
|
version: 1.8.3
|
88
99
|
type: :development
|
89
100
|
prerelease: false
|
90
|
-
version_requirements: *
|
101
|
+
version_requirements: *70100670813540
|
91
102
|
- !ruby/object:Gem::Dependency
|
92
103
|
name: simplecov
|
93
|
-
requirement: &
|
104
|
+
requirement: &70100670812840 !ruby/object:Gem::Requirement
|
94
105
|
none: false
|
95
106
|
requirements:
|
96
107
|
- - ! '>='
|
@@ -98,21 +109,21 @@ dependencies:
|
|
98
109
|
version: '0'
|
99
110
|
type: :development
|
100
111
|
prerelease: false
|
101
|
-
version_requirements: *
|
112
|
+
version_requirements: *70100670812840
|
102
113
|
- !ruby/object:Gem::Dependency
|
103
114
|
name: log4r
|
104
|
-
requirement: &
|
115
|
+
requirement: &70100670812100 !ruby/object:Gem::Requirement
|
105
116
|
none: false
|
106
117
|
requirements:
|
107
|
-
- -
|
118
|
+
- - ! '>='
|
108
119
|
- !ruby/object:Gem::Version
|
109
120
|
version: 1.1.10
|
110
121
|
type: :development
|
111
122
|
prerelease: false
|
112
|
-
version_requirements: *
|
123
|
+
version_requirements: *70100670812100
|
113
124
|
- !ruby/object:Gem::Dependency
|
114
125
|
name: msgpack
|
115
|
-
requirement: &
|
126
|
+
requirement: &70100670811380 !ruby/object:Gem::Requirement
|
116
127
|
none: false
|
117
128
|
requirements:
|
118
129
|
- - ! '>='
|
@@ -120,10 +131,10 @@ dependencies:
|
|
120
131
|
version: 0.4.6
|
121
132
|
type: :development
|
122
133
|
prerelease: false
|
123
|
-
version_requirements: *
|
134
|
+
version_requirements: *70100670811380
|
124
135
|
- !ruby/object:Gem::Dependency
|
125
136
|
name: eventmachine
|
126
|
-
requirement: &
|
137
|
+
requirement: &70100670810700 !ruby/object:Gem::Requirement
|
127
138
|
none: false
|
128
139
|
requirements:
|
129
140
|
- - ! '>='
|
@@ -131,18 +142,18 @@ dependencies:
|
|
131
142
|
version: 0.12.10
|
132
143
|
type: :development
|
133
144
|
prerelease: false
|
134
|
-
version_requirements: *
|
145
|
+
version_requirements: *70100670810700
|
135
146
|
- !ruby/object:Gem::Dependency
|
136
147
|
name: girl_friday
|
137
|
-
requirement: &
|
148
|
+
requirement: &70100670809960 !ruby/object:Gem::Requirement
|
138
149
|
none: false
|
139
150
|
requirements:
|
140
|
-
- -
|
151
|
+
- - ! '>='
|
141
152
|
- !ruby/object:Gem::Version
|
142
153
|
version: 0.9.7
|
143
154
|
type: :development
|
144
155
|
prerelease: false
|
145
|
-
version_requirements: *
|
156
|
+
version_requirements: *70100670809960
|
146
157
|
description: Event-Driven SOA with CQRS
|
147
158
|
email: benjaminlyu@gmail.com
|
148
159
|
executables: []
|
@@ -164,12 +175,8 @@ files:
|
|
164
175
|
- lib/serf/builder.rb
|
165
176
|
- lib/serf/command.rb
|
166
177
|
- lib/serf/error.rb
|
167
|
-
- lib/serf/message.rb
|
168
|
-
- lib/serf/messages/caught_exception_event.rb
|
169
|
-
- lib/serf/messages/message_accepted_event.rb
|
170
178
|
- lib/serf/middleware/uuid_tagger.rb
|
171
179
|
- lib/serf/more/command_worker.rb
|
172
|
-
- lib/serf/more/uuid_fields.rb
|
173
180
|
- lib/serf/routing/endpoint.rb
|
174
181
|
- lib/serf/routing/registry.rb
|
175
182
|
- lib/serf/runners/direct.rb
|
@@ -178,12 +185,15 @@ files:
|
|
178
185
|
- lib/serf/runners/helper.rb
|
179
186
|
- lib/serf/serfer.rb
|
180
187
|
- lib/serf/util/error_handling.rb
|
188
|
+
- lib/serf/util/mash_factory.rb
|
181
189
|
- lib/serf/util/null_object.rb
|
182
190
|
- lib/serf/util/options_extraction.rb
|
183
191
|
- lib/serf/util/protected_call.rb
|
184
192
|
- lib/serf/util/regexp_matcher.rb
|
185
193
|
- lib/serf/util/uuidable.rb
|
186
194
|
- lib/serf/version.rb
|
195
|
+
- schemas/caught_exception_event.json
|
196
|
+
- schemas/message_accepted_event.json
|
187
197
|
- serf.gemspec
|
188
198
|
- spec/serf_spec.rb
|
189
199
|
- spec/spec_helper.rb
|
@@ -202,7 +212,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
202
212
|
version: '0'
|
203
213
|
segments:
|
204
214
|
- 0
|
205
|
-
hash:
|
215
|
+
hash: 2754574147578555547
|
206
216
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
207
217
|
none: false
|
208
218
|
requirements:
|
data/lib/serf/message.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
require 'active_support/concern'
|
2
|
-
require 'active_support/core_ext/class/attribute'
|
3
|
-
require 'active_support/core_ext/string/inflections'
|
4
|
-
|
5
|
-
module Serf
|
6
|
-
|
7
|
-
##
|
8
|
-
# A module to represent a message that we're transporting over
|
9
|
-
# the wire. This is mainly for commands and events in ED-SOA.
|
10
|
-
# Optional, but useful for validations, etc.
|
11
|
-
#
|
12
|
-
module Message
|
13
|
-
extend ActiveSupport::Concern
|
14
|
-
|
15
|
-
included do
|
16
|
-
class_attribute :kind
|
17
|
-
send 'kind=', self.to_s.tableize.singularize
|
18
|
-
class_attribute :model_name
|
19
|
-
send 'model_name=', self.to_s
|
20
|
-
end
|
21
|
-
|
22
|
-
def to_hash
|
23
|
-
attributes.merge kind: kind
|
24
|
-
end
|
25
|
-
|
26
|
-
def to_msgpack
|
27
|
-
to_hash.to_msgpack
|
28
|
-
end
|
29
|
-
|
30
|
-
def to_json(*args)
|
31
|
-
to_hash.to_json *args
|
32
|
-
end
|
33
|
-
|
34
|
-
def model
|
35
|
-
self.class
|
36
|
-
end
|
37
|
-
|
38
|
-
def full_error_messages
|
39
|
-
errors.full_messages.join '. '
|
40
|
-
end
|
41
|
-
|
42
|
-
module ClassMethods
|
43
|
-
|
44
|
-
def parse(*args, &block)
|
45
|
-
self.new *args, &block
|
46
|
-
end
|
47
|
-
|
48
|
-
def build(*args, &block)
|
49
|
-
self.new *args, &block
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'serf/message'
|
2
|
-
require 'serf/util/uuidable'
|
3
|
-
|
4
|
-
module Serf
|
5
|
-
module Messages
|
6
|
-
|
7
|
-
##
|
8
|
-
# An event message to signal that the serf code caught an
|
9
|
-
# exception during the processing of some message, which is
|
10
|
-
# represented by the context field.
|
11
|
-
#
|
12
|
-
# Instances of this class are norminally pushed to an
|
13
|
-
# error channel for out of band processing/notification.
|
14
|
-
#
|
15
|
-
class CaughtExceptionEvent
|
16
|
-
include Serf::Message
|
17
|
-
include Serf::Util::Uuidable
|
18
|
-
|
19
|
-
attr_accessor :context
|
20
|
-
attr_accessor :error
|
21
|
-
attr_accessor :message
|
22
|
-
attr_accessor :backtrace
|
23
|
-
|
24
|
-
def initialize(options={})
|
25
|
-
@context = options[:context]
|
26
|
-
@error = options[:error]
|
27
|
-
@message = options[:message]
|
28
|
-
@backtrace = options[:backtrace]
|
29
|
-
@uuid = options[:uuid]
|
30
|
-
end
|
31
|
-
|
32
|
-
def attributes
|
33
|
-
{
|
34
|
-
'context' => @context,
|
35
|
-
'error' => @error,
|
36
|
-
'message' => @message,
|
37
|
-
'backtrace' => @backtrace,
|
38
|
-
'uuid' => (@uuid || create_coded_uuid)
|
39
|
-
}
|
40
|
-
end
|
41
|
-
|
42
|
-
def to_s
|
43
|
-
to_hash.to_s
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'serf/message'
|
2
|
-
require 'serf/util/uuidable'
|
3
|
-
|
4
|
-
module Serf
|
5
|
-
module Messages
|
6
|
-
|
7
|
-
##
|
8
|
-
# This event signals that the serf process has accepted a message
|
9
|
-
# for processing at a later time. These events are normally sent
|
10
|
-
# in response to calling clients, which is a separate signal
|
11
|
-
# than any errors given.
|
12
|
-
#
|
13
|
-
class MessageAcceptedEvent
|
14
|
-
include Serf::Message
|
15
|
-
include Serf::Util::Uuidable
|
16
|
-
|
17
|
-
attr_accessor :message
|
18
|
-
|
19
|
-
def initialize(options={})
|
20
|
-
@message = options[:message]
|
21
|
-
@uuid = options[:uuid]
|
22
|
-
end
|
23
|
-
|
24
|
-
def attributes
|
25
|
-
{
|
26
|
-
'message' => @message,
|
27
|
-
'uuid' => (@uuid || create_coded_uuid)
|
28
|
-
}
|
29
|
-
end
|
30
|
-
|
31
|
-
def to_s
|
32
|
-
to_hash.to_s
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
38
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'serf/util/uuidable'
|
2
|
-
|
3
|
-
module Serf
|
4
|
-
module More
|
5
|
-
|
6
|
-
##
|
7
|
-
# Assumes that Virtus has already been included in the class that
|
8
|
-
# also includes UuidFields.
|
9
|
-
#
|
10
|
-
module UuidFields
|
11
|
-
extend Serf::Util::Uuidable
|
12
|
-
|
13
|
-
def self.included(base)
|
14
|
-
base.attribute :uuid, String, default: lambda { |o,a| create_coded_uuid }
|
15
|
-
base.attribute :parent_uuid, String
|
16
|
-
base.attribute :origin_uuid, String
|
17
|
-
end
|
18
|
-
|
19
|
-
def create_child_uuids
|
20
|
-
{
|
21
|
-
uuid: UuidFields.create_coded_uuid,
|
22
|
-
parent_uuid: uuid,
|
23
|
-
origin_uuid: (origin_uuid || parent_uuid || uuid)
|
24
|
-
}
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
end
|