serf 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/serf/builder.rb CHANGED
@@ -139,7 +139,7 @@ module Serf
139
139
  # to be passed to Endpoint#build methods.
140
140
  def serf_options
141
141
  {
142
- response_channel: @error_channel,
142
+ response_channel: @response_channel,
143
143
  error_channel: @error_channel,
144
144
  logger: @logger
145
145
  }
data/lib/serf/command.rb CHANGED
@@ -73,7 +73,7 @@ module Serf
73
73
  # Now we allocate the object, and do some options extraction that may
74
74
  # modify the args array by popping off the last element if it is a hash.
75
75
  obj = allocate
76
- obj.send :__send__, :extract_options!, args
76
+ obj.__send__ :extract_options!, args
77
77
 
78
78
  # If the request was a hash, we MAY be able to convert it into a
79
79
  # request object. We only do this if a request_factory was set either
@@ -92,7 +92,7 @@ module Serf
92
92
  obj.validate_request!
93
93
 
94
94
  # Finalize the object's construction with the rest of the args & block.
95
- obj.send :__send__, :initialize, *args, &block
95
+ obj.__send__ :initialize, *args, &block
96
96
 
97
97
  return obj
98
98
  end
data/lib/serf/message.rb CHANGED
@@ -19,10 +19,6 @@ module Serf
19
19
  send 'model_name=', self.to_s
20
20
  end
21
21
 
22
- def kind
23
- self.class.kind
24
- end
25
-
26
22
  def to_hash
27
23
  attributes.merge kind: kind
28
24
  end
@@ -13,8 +13,8 @@ module Messages
13
13
  # error channel for out of band processing/notification.
14
14
  #
15
15
  class CaughtExceptionEvent
16
- include ::Serf::Message
17
- include ::Serf::Util::Uuidable
16
+ include Serf::Message
17
+ include Serf::Util::Uuidable
18
18
 
19
19
  attr_accessor :context
20
20
  attr_accessor :error
@@ -35,7 +35,7 @@ module Messages
35
35
  'error' => @error,
36
36
  'message' => @message,
37
37
  'backtrace' => @backtrace,
38
- 'uuid' => uuid
38
+ 'uuid' => (@uuid || create_coded_uuid)
39
39
  }
40
40
  end
41
41
 
@@ -11,8 +11,8 @@ module Messages
11
11
  # than any errors given.
12
12
  #
13
13
  class MessageAcceptedEvent
14
- include ::Serf::Message
15
- include ::Serf::Util::Uuidable
14
+ include Serf::Message
15
+ include Serf::Util::Uuidable
16
16
 
17
17
  attr_accessor :message
18
18
 
@@ -24,7 +24,7 @@ module Messages
24
24
  def attributes
25
25
  {
26
26
  'message' => @message,
27
- 'uuid' => uuid
27
+ 'uuid' => (@uuid || create_coded_uuid)
28
28
  }
29
29
  end
30
30
 
@@ -1,4 +1,4 @@
1
- require 'uuidtools'
1
+ require 'serf/util/uuidable'
2
2
 
3
3
  module Serf
4
4
  module Middleware
@@ -9,6 +9,7 @@ module Middleware
9
9
  # if the incoming request already has it.
10
10
  #
11
11
  class UuidTagger
12
+ include Serf::Util::Uuidable
12
13
 
13
14
  ##
14
15
  # @param app the app
@@ -16,12 +17,14 @@ module Middleware
16
17
  #
17
18
  def initialize(app, options={})
18
19
  @app = app
19
- @field = options.fetch(:field) { 'serf.request_uuid' }
20
+ @field = options.fetch(:field) { 'uuid' }
20
21
  end
21
22
 
22
23
  def call(env)
23
24
  env = env.dup
24
- env[@field] ||= UUIDTools::UUID.random_create.to_s
25
+ unless env[@field.to_sym] || env[@field.to_s]
26
+ env[@field] = create_coded_uuid
27
+ end
25
28
  @app.call env
26
29
  end
27
30
 
@@ -0,0 +1,51 @@
1
+ require 'serf/command'
2
+ require 'serf/util/error_handling'
3
+
4
+ module Serf
5
+ module More
6
+
7
+ ##
8
+ # Creates a proc (CommandWorker.worker) that will be used by
9
+ # GirlFriday WorkQueues. This proc will receive messages from
10
+ # GirlFriday and will (1) create a CommandWorker instance with the
11
+ # given message and (2) execute (#call) said CommandWorker instance.
12
+ # The CommandWorker instance assumes that the received message is
13
+ # a callable (#call) object, and will execute that object's 'call' method.
14
+ #
15
+ # The purpose of this is so we can build Command objects in one
16
+ # context/thread and have it actually executed in a separate threadpool.
17
+ #
18
+ # Example:
19
+ #
20
+ # # Creates the GirlFriday work queue.
21
+ # command_worker_queue = GirlFriday::WorkQueue.new(
22
+ # CommandWorker.worker(
23
+ # logger: my_logger,
24
+ # response_channel: response_channel,
25
+ # error_channel: error_channel))
26
+ #
27
+ # # In some place that receives requests and generates commands.
28
+ # # Push the command into the command workqueue for async processing.
29
+ # command_worker_queue.push MyCommand.build(REQUEST_HASH)
30
+ #
31
+ class CommandWorker
32
+ include Serf::Command
33
+ include Serf::ErrorHandling
34
+
35
+ def call
36
+ ok, results = with_error_handling do
37
+ request.call
38
+ end
39
+ return results
40
+ end
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
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,29 @@
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
@@ -60,11 +60,11 @@ module Runners
60
60
  # queue.
61
61
  #
62
62
  def perform(task)
63
- with_error_handling(task[:context]) do
63
+ ok, run_result = with_error_handling(task[:context]) do
64
64
  task[:handler].call
65
- run_result = run_result.is_a?(Hash) ? [run_result] : Array(run_result)
66
- push_results run_result
67
65
  end
66
+ run_result = run_result.is_a?(Hash) ? [run_result] : Array(run_result)
67
+ push_results run_result if ok
68
68
  end
69
69
 
70
70
  end
@@ -3,6 +3,7 @@ require 'active_support/core_ext/string/inflections'
3
3
  require 'serf/messages/caught_exception_event'
4
4
  require 'serf/util/null_object'
5
5
  require 'serf/util/options_extraction'
6
+ require 'serf/util/protected_call'
6
7
 
7
8
  module Serf
8
9
  module Util
@@ -11,21 +12,34 @@ module Util
11
12
  # Helper module to rescues exceptions from executing blocks of
12
13
  # code, and then logs+pushes the error event.
13
14
  #
15
+ # Including classes may have the following instance variables
16
+ # to override the default values:
17
+ # * @error_event_class - ::Serf::Messages::CaughtExceptionEvent
18
+ # * @logger - ::Serf::Util::NullObject.new
19
+ # * @error_channel - ::Serf::Util::NullObject.new
14
20
  module ErrorHandling
15
- include ::Serf::Util::OptionsExtraction
21
+ include Serf::Util::OptionsExtraction
22
+ include Serf::Util::ProtectedCall
16
23
 
17
24
  ##
18
25
  # A block wrapper to handle errors when executing a block.
19
26
  #
20
- # Including classes may have the following instance variables
21
- # to override the default values:
22
- # * @error_event_class - ::Serf::Messages::CaughtExceptionEvent
23
- # * @logger - ::Serf::Util::NullObject.new
24
- # * @error_channel - ::Serf::Util::NullObject.new
27
+ def with_error_handling(context=nil, errback=:handle_error, &block)
28
+ ok, results = protected_call &block
29
+ return ok, (ok ?
30
+ results :
31
+ ((errback.is_a?(Proc) ?
32
+ errback.call(results, context) :
33
+ send(errback, results, context))))
34
+ end
35
+
36
+ ##
37
+ # Including classes may override this method to do alternate error
38
+ # handling. By default, this method will create a new caught exception
39
+ # event and publish it to the error channel. This method will also
40
+ # log the exception itself to the logger.
25
41
  #
26
- def with_error_handling(context=nil)
27
- return true, yield
28
- rescue => e
42
+ def handle_error(e, context=nil)
29
43
  eec = opts :error_event_class, ::Serf::Messages::CaughtExceptionEvent
30
44
  logger = opts :logger, ::Serf::Util::NullObject.new
31
45
  error_channel = opts :error_channel, ::Serf::Util::NullObject.new
@@ -35,20 +49,18 @@ module Util
35
49
  message: e.message,
36
50
  backtrace: e.backtrace.join("\n"))
37
51
 
38
- # log the error to our logger, and to our error channel.
39
- logger.error error_event
52
+ # log the error to our logger
53
+ logger.error e
54
+
55
+ # log the error event to our error channel.
40
56
  begin
41
57
  error_channel.push error_event
42
58
  rescue => e1
43
- logger.error("
44
- Failed pushing to ErrorChannel:
45
- #{e1.message}
46
- #{e1.backtrace.join('\n')}
47
- ")
59
+ logger.error e1
48
60
  end
49
61
 
50
62
  # We're done, so just return this error.
51
- return false, error_event
63
+ return error_event
52
64
  end
53
65
 
54
66
  end
@@ -0,0 +1,35 @@
1
+ module Serf
2
+ module Util
3
+
4
+ ##
5
+ # Rescues exceptions raised when calling blocks.
6
+ #
7
+ module ProtectedCall
8
+
9
+ ##
10
+ # A block wrapper to catch errors when executing a block. Instead of
11
+ # raising the error, the error is caught and returned in place of
12
+ # the block's results.
13
+ #
14
+ # ok, results = protected_call do
15
+ # 1 + 1
16
+ # end
17
+ # => [true, 2]
18
+ #
19
+ # ok, results = protected_call do
20
+ # raise 'My Error'
21
+ # end
22
+ # => [false, RuntimeError]
23
+ #
24
+ # @return boolean success and the block's (or caught exception) results.
25
+ #
26
+ def protected_call
27
+ return true, yield
28
+ rescue => e
29
+ return false, e
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
@@ -1,15 +1,37 @@
1
+ require 'base64'
1
2
  require 'uuidtools'
2
3
 
3
4
  module Serf
4
5
  module Util
5
6
 
6
7
  ##
7
- # Helper module to include UUIDs as message fields.
8
+ # Helper module to for various UUID tasks.
9
+ #
10
+ # 1. Primarily to create and parse 'coded' UUIDs, which are just
11
+ # base64 encoded UUIDs without trailing '='.
8
12
  #
9
13
  module Uuidable
10
14
 
11
- def uuid
12
- @uuid ||= UUIDTools::UUID.random_create.to_s
15
+ ##
16
+ # Creates a Timestamp UUID, base64 encoded.
17
+ #
18
+ # NOTE: UUIDTools TimeStamp code creates a UTC based timestamp UUID.
19
+ #
20
+ def create_coded_uuid
21
+ # All raw UUIDs are 16 bytes long. Base64 lengthens the string to
22
+ # 24 bytes long. We chomp off the last two equal signs '==' to
23
+ # trim the string length to 22 bytes. This gives us an overhead
24
+ # of an extra 6 bytes over raw UUID, but with the readability
25
+ # benefit. And saves us 14 bytes of size from the 'standard'
26
+ # string hex representation of UUIDs.
27
+ Base64.urlsafe_encode64(UUIDTools::UUID.timestamp_create.raw).chomp('==')
28
+ end
29
+
30
+ ##
31
+ # @param coded_uuid a coded uuid to parse.
32
+ #
33
+ def parse_coded_uuid(coded_uuid)
34
+ UUIDTools::UUID.parse_raw Base64.urlsafe_decode64("#{coded_uuid}==")
13
35
  end
14
36
 
15
37
  end
data/lib/serf/version.rb CHANGED
@@ -2,7 +2,7 @@ module Serf
2
2
 
3
3
  module Version
4
4
  MAJOR = 0
5
- MINOR = 7
5
+ MINOR = 8
6
6
  PATCH = 0
7
7
  BUILD = nil
8
8
  STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join '.'
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.7.0"
8
+ s.version = "0.8.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-03-13"
12
+ s.date = "2012-04-19"
13
13
  s.description = "Event-Driven SOA with CQRS"
14
14
  s.email = "benjaminlyu@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -34,6 +34,8 @@ Gem::Specification.new do |s|
34
34
  "lib/serf/messages/caught_exception_event.rb",
35
35
  "lib/serf/messages/message_accepted_event.rb",
36
36
  "lib/serf/middleware/uuid_tagger.rb",
37
+ "lib/serf/more/command_worker.rb",
38
+ "lib/serf/more/uuid_fields.rb",
37
39
  "lib/serf/routing/endpoint.rb",
38
40
  "lib/serf/routing/registry.rb",
39
41
  "lib/serf/runners/direct.rb",
@@ -44,6 +46,7 @@ Gem::Specification.new do |s|
44
46
  "lib/serf/util/error_handling.rb",
45
47
  "lib/serf/util/null_object.rb",
46
48
  "lib/serf/util/options_extraction.rb",
49
+ "lib/serf/util/protected_call.rb",
47
50
  "lib/serf/util/regexp_matcher.rb",
48
51
  "lib/serf/util/uuidable.rb",
49
52
  "lib/serf/version.rb",
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.7.0
4
+ version: 0.8.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-03-13 00:00:00.000000000 Z
12
+ date: 2012-04-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
16
- requirement: &70285339872700 !ruby/object:Gem::Requirement
16
+ requirement: &70198112141080 !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: *70285339872700
24
+ version_requirements: *70198112141080
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: i18n
27
- requirement: &70285339872080 !ruby/object:Gem::Requirement
27
+ requirement: &70198112140280 !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: *70285339872080
35
+ version_requirements: *70198112140280
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: uuidtools
38
- requirement: &70285339871240 !ruby/object:Gem::Requirement
38
+ requirement: &70198112138420 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 2.1.2
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70285339871240
46
+ version_requirements: *70198112138420
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec
49
- requirement: &70285339870220 !ruby/object:Gem::Requirement
49
+ requirement: &70198112136940 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 2.8.0
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70285339870220
57
+ version_requirements: *70198112136940
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: yard
60
- requirement: &70285339869440 !ruby/object:Gem::Requirement
60
+ requirement: &70198112135260 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 0.7.5
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70285339869440
68
+ version_requirements: *70198112135260
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: bundler
71
- requirement: &70285339868840 !ruby/object:Gem::Requirement
71
+ requirement: &70198112134580 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ~>
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: 1.0.22
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70285339868840
79
+ version_requirements: *70198112134580
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: jeweler
82
- requirement: &70285339868260 !ruby/object:Gem::Requirement
82
+ requirement: &70198112148060 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ~>
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: 1.8.3
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70285339868260
90
+ version_requirements: *70198112148060
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: simplecov
93
- requirement: &70285339867680 !ruby/object:Gem::Requirement
93
+ requirement: &70198112146140 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70285339867680
101
+ version_requirements: *70198112146140
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: log4r
104
- requirement: &70285339866960 !ruby/object:Gem::Requirement
104
+ requirement: &70198112145040 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ~>
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: 1.1.10
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *70285339866960
112
+ version_requirements: *70198112145040
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: msgpack
115
- requirement: &70285339866280 !ruby/object:Gem::Requirement
115
+ requirement: &70198112144400 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ! '>='
@@ -120,10 +120,10 @@ dependencies:
120
120
  version: 0.4.6
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *70285339866280
123
+ version_requirements: *70198112144400
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: eventmachine
126
- requirement: &70285339914940 !ruby/object:Gem::Requirement
126
+ requirement: &70198112143700 !ruby/object:Gem::Requirement
127
127
  none: false
128
128
  requirements:
129
129
  - - ! '>='
@@ -131,10 +131,10 @@ dependencies:
131
131
  version: 0.12.10
132
132
  type: :development
133
133
  prerelease: false
134
- version_requirements: *70285339914940
134
+ version_requirements: *70198112143700
135
135
  - !ruby/object:Gem::Dependency
136
136
  name: girl_friday
137
- requirement: &70285339914320 !ruby/object:Gem::Requirement
137
+ requirement: &70198112142640 !ruby/object:Gem::Requirement
138
138
  none: false
139
139
  requirements:
140
140
  - - ~>
@@ -142,7 +142,7 @@ dependencies:
142
142
  version: 0.9.7
143
143
  type: :development
144
144
  prerelease: false
145
- version_requirements: *70285339914320
145
+ version_requirements: *70198112142640
146
146
  description: Event-Driven SOA with CQRS
147
147
  email: benjaminlyu@gmail.com
148
148
  executables: []
@@ -168,6 +168,8 @@ files:
168
168
  - lib/serf/messages/caught_exception_event.rb
169
169
  - lib/serf/messages/message_accepted_event.rb
170
170
  - lib/serf/middleware/uuid_tagger.rb
171
+ - lib/serf/more/command_worker.rb
172
+ - lib/serf/more/uuid_fields.rb
171
173
  - lib/serf/routing/endpoint.rb
172
174
  - lib/serf/routing/registry.rb
173
175
  - lib/serf/runners/direct.rb
@@ -178,6 +180,7 @@ files:
178
180
  - lib/serf/util/error_handling.rb
179
181
  - lib/serf/util/null_object.rb
180
182
  - lib/serf/util/options_extraction.rb
183
+ - lib/serf/util/protected_call.rb
181
184
  - lib/serf/util/regexp_matcher.rb
182
185
  - lib/serf/util/uuidable.rb
183
186
  - lib/serf/version.rb
@@ -199,7 +202,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
199
202
  version: '0'
200
203
  segments:
201
204
  - 0
202
- hash: 314755585934468655
205
+ hash: 3739935025256924512
203
206
  required_rubygems_version: !ruby/object:Gem::Requirement
204
207
  none: false
205
208
  requirements: