serf 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/.gitignore +21 -0
  2. data/.travis.yml +7 -0
  3. data/Gemfile +20 -26
  4. data/Guardfile +16 -0
  5. data/NOTICE.txt +1 -1
  6. data/README.md +223 -207
  7. data/Rakefile +3 -18
  8. data/lib/serf/builder.rb +31 -136
  9. data/lib/serf/errors/policy_failure.rb +10 -0
  10. data/lib/serf/middleware/error_handler.rb +53 -0
  11. data/lib/serf/middleware/parcel_freezer.rb +36 -0
  12. data/lib/serf/middleware/parcel_masher.rb +39 -0
  13. data/lib/serf/middleware/policy_checker.rb +31 -0
  14. data/lib/serf/middleware/uuid_tagger.rb +13 -11
  15. data/lib/serf/parcel_builder.rb +30 -0
  16. data/lib/serf/serfer.rb +27 -66
  17. data/lib/serf/util/error_handling.rb +13 -36
  18. data/lib/serf/util/protected_call.rb +2 -2
  19. data/lib/serf/util/uuidable.rb +14 -38
  20. data/lib/serf/version.rb +1 -1
  21. data/schemas/{caught_exception_event.json → serf/events/caught_error.json} +4 -7
  22. data/serf.gemspec +22 -101
  23. data/spec/serf/builder_spec.rb +44 -0
  24. data/spec/serf/errors/policy_failure_spec.rb +11 -0
  25. data/spec/serf/middleware/error_handler_spec.rb +48 -0
  26. data/spec/serf/middleware/parcel_freezer_spec.rb +20 -0
  27. data/spec/serf/middleware/parcel_masher_spec.rb +30 -0
  28. data/spec/serf/middleware/policy_checker_spec.rb +70 -0
  29. data/spec/serf/middleware/uuid_tagger_spec.rb +32 -0
  30. data/spec/serf/parcel_builder_spec.rb +46 -0
  31. data/spec/serf/serfer_spec.rb +61 -0
  32. data/spec/serf/util/error_handling_spec.rb +35 -0
  33. data/spec/serf/util/null_object_spec.rb +26 -0
  34. data/spec/serf/util/options_extraction_spec.rb +62 -0
  35. data/spec/serf/util/protected_call_spec.rb +33 -0
  36. data/spec/serf/util/uuidable_spec.rb +56 -0
  37. data/spec/serf_spec.rb +1 -4
  38. data/spec/spec_helper.rb +3 -0
  39. data/spec/support/error_handling_wrapper.rb +5 -0
  40. data/spec/support/factories.rb +32 -0
  41. data/spec/support/failing_policy.rb +9 -0
  42. data/spec/support/json_schema_tester.rb +14 -0
  43. data/spec/support/options_extraction_wrapper.rb +10 -0
  44. data/spec/support/passing_policy.rb +7 -0
  45. data/spec/support/protected_call_wrapper.rb +5 -0
  46. metadata +81 -131
  47. data/.document +0 -5
  48. data/.rspec +0 -1
  49. data/Gemfile.lock +0 -58
  50. data/docs/thread_pools.txt +0 -16
  51. data/lib/serf/command.rb +0 -79
  52. data/lib/serf/error.rb +0 -11
  53. data/lib/serf/errors/not_found.rb +0 -8
  54. data/lib/serf/middleware/girl_friday_async.rb +0 -39
  55. data/lib/serf/middleware/masherize.rb +0 -25
  56. data/lib/serf/routing/regexp_matcher.rb +0 -35
  57. data/lib/serf/routing/route.rb +0 -35
  58. data/lib/serf/routing/route_set.rb +0 -64
  59. data/schemas/message_accepted_event.json +0 -14
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ # Gemfile.lock because this is a library, not a deployable application.
2
+ Gemfile.lock
3
+
4
+ # rcov generated
5
+ coverage
6
+
7
+ # rdoc generated
8
+ rdoc
9
+
10
+ # yard generated
11
+ doc
12
+ .yardoc
13
+
14
+ # bundler config
15
+ .bundle
16
+
17
+ # bundler installs here if bundle path is set to "vendor"
18
+ vendor
19
+
20
+ # generated builds
21
+ pkg
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.2"
4
+ - "1.9.3"
5
+ - jruby-19mode # JRuby in 1.9 mode
6
+ - rbx-19mode
7
+ script: bundle exec rake spec
data/Gemfile CHANGED
@@ -1,35 +1,29 @@
1
1
  source 'http://rubygems.org'
2
- # Add dependencies required to use your gem here.
3
- # Example:
4
- # gem 'activesupport', '>= 2.3.5'
5
2
 
6
- # Requirements for both clients and servers.
7
- gem 'activesupport', '>= 3.2.0'
8
- gem 'i18n', '>= 0.6.0' # For ActiveSupport
9
- gem 'hashie', ">= 1.2.0"
10
- # Used by Serf::Messages::*
11
- gem 'uuidtools', '>= 2.1.2'
3
+ # Runtime dependencies specified in gemspec
4
+ gemspec
12
5
 
13
- # Add dependencies to develop your gem here.
14
- # Include everything needed to run rake, tests, features, etc.
6
+ # Development and Testing dependencies
15
7
  group :development, :test do
16
- gem "rspec", "~> 2.8.0"
17
- gem "yard", "~> 0.7.5"
18
- gem "bundler", "~> 1.1.3"
19
- gem "jeweler", "~> 1.8.3"
20
- gem 'simplecov', '>= 0'
8
+ gem 'bundler'
9
+ gem 'rake'
21
10
 
22
- # For our testing
23
- gem 'log4r', '>= 1.1.10'
11
+ # Requirements to run our tests and metrics and docs generation
12
+ gem 'fuubar'
13
+ gem 'guard'
14
+ gem 'guard-rspec'
15
+ gem 'rspec'
16
+ gem 'yard'
17
+ gem 'simplecov', require: false
24
18
 
25
- # Soft Dependencies
26
- #gem 'log4r', '~> 1.1.9'
27
- gem 'msgpack', '>= 0.4.6'
28
- #gem 'multi_json', '~> 1.0.3'
19
+ # Required to support testing
20
+ gem 'factory_girl'
29
21
 
30
- # For Server Side of things
22
+ # Required by Guard
23
+ gem 'rb-inotify', require: false
24
+ gem 'rb-fsevent', require: false
25
+ gem 'rb-fchange', require: false
31
26
 
32
- # EventMachine is now optional runner
33
- gem 'eventmachine', '>= 0.12.10'
34
- gem 'girl_friday', '>= 0.9.7'
27
+ # Required by our Specs
28
+ gem 'json-schema'
35
29
  end
data/Guardfile ADDED
@@ -0,0 +1,16 @@
1
+ guard(
2
+ :rspec,
3
+ cli: '--format Fuubar --color',
4
+ all_on_start: true,
5
+ all_after_pass: false,
6
+ :version => 2) do
7
+
8
+ # Watch our specs
9
+ watch(%r{^spec/.+_spec\.rb$})
10
+
11
+ # Watch our lib directory, and run the matching spec
12
+ watch(%r{^lib/(.+)\.rb$}) { |m|
13
+ "spec/#{m[1]}_spec.rb"
14
+ }
15
+
16
+ end
data/NOTICE.txt CHANGED
@@ -1,4 +1,4 @@
1
1
  Serf
2
- Copyright 2011 Benjamin Yu
2
+ Copyright 2011-2012 Benjamin Yu
3
3
  This software includes code written by Benjamin Yu <http://benjaminyu.org/>
4
4
  covered under the Apache License <http://www.apache.org/licenses/LICENSE-2.0>.
data/README.md CHANGED
@@ -1,82 +1,193 @@
1
1
  serf
2
2
  ====
3
3
 
4
- Serf is simply a Rack-like library that, when called, routes received
5
- messages (requests or events) to "Command" handlers.
4
+ Code your Interactors with policy protection.
6
5
 
7
- The pattern of Command objects and messaging gives us nice primatives
8
- for Event-Driven Service Oriented Architecture in combination with
9
- the Command Query Responsibility Separation pattern.
6
+ Serf Links
7
+ ----------
10
8
 
11
- Philosophy
9
+ * Source: https://github.com/byu/serf
10
+ * Continuous Integration: https://travis-ci.org/byu/serf
11
+ * [![Build Status](https://secure.travis-ci.org/byu/serf.png)](http://travis-ci.org/byu/serf)
12
+ * RubyGems: http://rubygems.org/gems/serf
13
+ * RubyDocs: http://rubydoc.info/gems/serf
14
+
15
+ Interactors
16
+ -----------
17
+
18
+ The piece of work to be done. This takes in a request, represented
19
+ by a "Message", and returns an "Event" as its result. The Interactor
20
+ is the "Domain Controller" with respect to performing
21
+ Domain Layer business logic in coordinating and interacting with
22
+ the Domain Layer's Entities (Value Objects and Entity Gateways).
23
+
24
+ 1. Include the "Serf::Interactor" module in your class.
25
+ 2. Implement the 'call(message)' method.
26
+ 3. Return the tuple: (message, kind)
27
+ a. Hashie::Mash is recommended for the message, nil is acceptable
28
+ b. The kind is the string representation of the message type,
29
+ It is optional.
30
+
31
+ Example:
32
+
33
+ require 'hashie'
34
+
35
+ class MyInteractor
36
+
37
+ def initialize(*contructor_params, &block)
38
+ # Do some validation here, or extra parameter setting with the args
39
+ @model = opts :model, MyModel
40
+ end
41
+
42
+ def call(message)
43
+ # Do something w/ the message and opts.
44
+ # Simple data structures for the Interactor's "Request".
45
+
46
+ item = @model.find message.model_id
47
+
48
+ # Make a simple data structure as the Interactor "Response".
49
+ response = Hashie::Mash.new
50
+ response.item = item
51
+ # Return the response 'kind' and the response data.
52
+ return response, 'my_app/events/did_something'
53
+ end
54
+ end
55
+
56
+
57
+ Parcels
58
+ -------
59
+
60
+ A Parcel is just the package of Headers and Message. Serf's convention
61
+ represents requests and responses as (mostly) just Plain Old Hash Objects
62
+ (POHO as opposed to PORO) over the Boundaries (see Architecture Lost Years).
63
+ This simplifies marshalling over the network. It also gives us easier
64
+ semantics in defining Request and Responses without need of extra classes,
65
+ code, etc.
66
+
67
+ The Parcel in Ruby (Datastructure) is represented simply as:
68
+
69
+ * A 2 element Hash: { headers: headers, message: message}.
70
+
71
+ NOTE: Hashie::Mash is *Awesome*. (https://github.com/intridea/hashie)
72
+ NOTE: Serf passes the parcel as frozen Hashie::Mash instances
73
+ to Interactor' call method by default.
74
+
75
+ *Messages* are the representation of a Business Request or Business Event.
76
+
77
+ In the parcel, the message is the business data. It specifies what
78
+ business work needs to be done, or what business was done.
79
+ Everything that an Interactor needs to execute its Use Case SHOULD
80
+ be in the message.
81
+
82
+ RECOMMENDED: Use JSON Schema to validate the structure of a message.
83
+ https://github.com/hoxworth/json-schema
84
+ This can be implemented in the 'Policy' chain.
85
+
86
+ *Headers* are the processing meta data that is associated with a Message.
87
+
88
+ Headers provide information that would assist in processing, tracking
89
+ a Message. But does not provide business relevant information to
90
+ the Request or Event Message.
91
+
92
+ RECOMMENDED: Recommended to be placed in headers is the 'kind' field.
93
+
94
+ The "kind" field identifies the ontological meaning of the message, which
95
+ may be used to route messages over messaging channels to Interactors.
96
+ The convention is 'mymodule/requests/my_business_request' for Requests,
97
+ and 'mymodule/events/my_business_event' for Events.
98
+
99
+ Examples are:
100
+ * UUIDs to track request and events, providing a sequential order of
101
+ execution of commands. (Already Implemented by Serf).
102
+ * Current User that sent the request. For authentication and authorization.
103
+ * Host and Application Server that is processing this request.
104
+
105
+ Generally, the header information is populated only by the infrastructure
106
+ that hosts the Interactors. The Interactors themselves do not
107
+ return any headers in the response. The Interactors are tasked to provide
108
+ only business relevant data in the Event messages they return.
109
+
110
+
111
+ Policies
112
+ --------
113
+
114
+ Serf implements Policy Chains to validate, check the incoming Parcels before
115
+ actually executing Interactors.
116
+
117
+ Example Benefits:
118
+ * Authorization to execute Command.
119
+ * Validation of Message schema
120
+
121
+ Policies only need to implement a single method:
122
+
123
+ def check!(parcel)
124
+ raise 'Failure' # To fail the policy, raise an error.
125
+ end
126
+
127
+ RECOMMENDED: Use `Serf::Errors::PolicyFailure` error type.
128
+
129
+
130
+ References
12
131
  ==========
13
132
 
14
- The underlying idea of Serf is to define a standard Ruby code interface
15
- that standalone gems can follow to create a business verticals services.
16
- These gems are intended to run as standalone processes in a distributed
17
- manner.
18
-
19
- Fundamentally, a service creates an abstraction of:
20
- 1. Messages
21
- 2. Handlers/Commands
22
-
23
- Messages are the representation of data, documents, etc that are
24
- marshalled from client to service, which represents the business
25
- level interaction of the service.
26
-
27
- Messages may be command requests that a service must handle.
28
- Messages may be events that a service emits.
29
- Messages may be documents that represent state or business data.
30
-
31
- Handlers are the code that is executed over Messages.
32
- Handlers may process Command Messages.
33
- Handlers may process observed Events that 3rd party services emit.
34
-
35
- Serf App and Channels
36
- =====================
37
-
38
- A Serf App is a Rack-like application that takes in an ENV hash with
39
- TWO important fields: message and context.
40
-
41
- The Message is the request or event. The data that is to be processed.
42
-
43
- The Context is meta data that needs to be taken into account about the
44
- processing of this data. The main important field may be a current user.
45
- Though, it is not explicitly defined.
46
-
47
- A request life cycle involves:
48
- 1. Submitting a message and context to the SerfApp
49
- 2. The Serf app will run middleware as defined by the DSL.
50
- 3. Matched routes are found for the message and context.
51
- 4. Run each route:
52
- a. Run the policy chain for each route (This is for ACLs)
53
- b. If no exception was raised, execute the route.
54
- 5. Return all non-nil results to the caller.
55
- a. Each result is a Message.
56
-
57
- If set in the DSL, the success and error responses may be published
58
- to a response and/or error channel.
59
-
60
-
61
- Service Libraries
62
- =================
63
-
64
- 1. Service Libraries SHOULD implement messages as just hashes with
65
- defined schemas (JSON Schema).
66
- a. Required by all messages is the 'kind' field.
67
- b. By default, Serf Commands will read in hashes and turn them into
68
- more convenient Hashie::Mash objects.
69
- 2. Serialization of the messages SHOULD BE Json or MessagePack (I hate XML).
70
- 3. Handlers MUST implement the 'build' class method.
71
- a. This can just be aliased to new. But is made explicit in case we have
72
- custom factories.
73
- 4. Handler methods SHOULD return zero or more messages.
74
- a. Raised errors are caught and pushed to error channels.
75
- b. Returned messages MUST be Hash based objects for Serialization.
76
- 5. Handler methods SHOULD handle catch their business logic exceptions and
77
- return them as specialized messages that can be forwarded down error channels.
78
- Uncaught exceptions that are then caught by Serf are pushed as
79
- generic CaughtExceptionEvents, and are harder to deal with.
133
+ Keynote: Architecture the Lost Years, by Robert Martin
134
+ * http://confreaks.com/videos/759
135
+ * http://vimeo.com/43612849
136
+
137
+ Domain Driven Design by Eric Evans:
138
+ * http://books.google.com/books?id=7dlaMs0SECsC&dq=domain+driven+design
139
+
140
+ Patterns of Enterprise Application Architecture by Martin Fowler
141
+ * http://martinfowler.com/books/eip.html
142
+ * Command (Unit of Work) Pattern
143
+ * Event Sourcing
144
+
145
+ Enterprise Integration Patterns by Hohpe and Woolf
146
+ * http://www.eaipatterns.com/
147
+
148
+ DDD for Rails Developers Series:
149
+ * http://rubysource.com/ddd-for-rails-developers-part-1-layered-architecture/
150
+ * http://rubysource.com/ddd-for-rails-developers-part-2-entities-and-values/
151
+ * http://rubysource.com/ddd-for-rails-developers-part-3-aggregates/
152
+
153
+ DCI in Ruby
154
+ * Maybe use DCI to better manage business logic in Entities.
155
+ * http://mikepackdev.com/blog_posts/24-the-right-way-to-code-dci-in-ruby
156
+ * http://mikepackdev.com/blog_posts/35-dci-with-ruby-refinements
157
+ * http://nicksda.apotomo.de/2011/12/ruby-on-rest-2-representers-and-the-dci-pattern/
158
+
159
+ CQRS
160
+ * http://www.udidahan.com/2009/12/09/clarified-cqrs/
161
+ * http://elegantcode.com/2009/11/11/cqrs-la-greg-young/
162
+ * http://elegantcode.com/2009/11/20/cqrs-the-domain-events/
163
+
164
+ Life beyond Distributed Transactions: an Apostate’s Opinion by Pat Helland
165
+ * http://www.ics.uci.edu/~cs223/papers/cidr07p15.pdf
166
+
167
+ Building on Quicksand by Pat Helland
168
+ * http://arxiv.org/ftp/arxiv/papers/0909/0909.1788.pdf
169
+
170
+ The Domain Layer (from DDD):
171
+
172
+ 1. Entities (Model Entities)- What your application is.
173
+ * Also remember Value Objects.
174
+ * How your Domain Model is structured, but NOT necessarily tied to the
175
+ underlying storage infrastructure.
176
+ * http://rubysource.com/ddd-for-rails-developers-part-2-entities-and-values/
177
+ 2. Domain Controllers (Interactors) - What your application does.
178
+ * The business logic of coordinating different entities.
179
+ Different than a Rails controller.
180
+ * Keynote: Architecture The Lost Years
181
+ Robert Martin
182
+ Ruby Midwest 2011
183
+ http://confreaks.com/videos/759
184
+ * Your Rails Application is Missing a Domain Controller
185
+ Nicholas Henry
186
+ http://blog.firsthand.ca/2011/12/your-rails-application-is-missing.html
187
+ 3. There is a balancing game of what business logic code lives in an
188
+ Entity vs a Domain Controller... Do what works for you.
189
+ But mostly follow "Use Cases" in Domain Controllers,
190
+ and "Application Agnostic Logic" in Entities.
80
191
 
81
192
 
82
193
  Example
@@ -87,170 +198,75 @@ Example
87
198
  require 'yell'
88
199
 
89
200
  require 'serf/builder'
90
- require 'serf/command'
91
- require 'serf/middleware/uuid_tagger'
92
- require 'serf/util/options_extraction'
93
201
 
94
202
  # create a simple logger for this example
95
- my_logger = Yell.new do |l|
96
- l.level = :debug
97
- l.adapter :datefile, 'my_production.log', :level => [:debug, :info, :warn]
98
- l.adapter :datefile, 'my_error.log', :level => Yell.level.gte(:error)
99
- end
100
-
101
- # Helper class for this example to receive result or error messages
102
- # and pipe it into our logger.
103
- class MyChannel
104
- def initialize(logger, error=false)
105
- @logger = logger
106
- @error = error
107
- end
108
- def push(message)
109
- if @error
110
- @logger.fatal "ERROR CHANNEL: #{message.to_json}"
111
- else
112
- @logger.debug "RESP CHANNEL: #{message.to_json}"
113
- end
114
- end
115
- end
203
+ my_logger = Yell.new STDOUT
116
204
 
117
205
  # my_lib/my_policy.rb
118
206
  class MyPolicy
119
207
 
120
- def check!(message, context)
121
- raise 'EXPECTED ERROR: Data is nil' if message[:data].nil?
122
- end
123
-
124
- def self.build(*args, &block)
125
- new *args, &block
208
+ def check!(parcel)
209
+ raise 'Policy Error: User is nil' unless parcel.headers.user
126
210
  end
127
211
 
128
212
  end
129
213
 
130
- # my_lib/my_overloaded_command.rb
131
- class MyOverloadedCommand
132
- include Serf::Command
133
-
134
- attr_reader :name
135
- attr_reader :do_raise
214
+ # my_lib/my_interactor.rb
215
+ class MyInteractor
136
216
 
137
- def initialize(*args)
138
- extract_options! args
139
- @name = opts! :name
140
- @do_raise = opts :raises, false
141
- end
142
-
143
- def call(request, context)
144
- # Just our name to sort things out
217
+ def call(message)
218
+ raise 'Error' if message.raise_an_error
145
219
 
146
- raise "EXPECTED ERROR: Forcing Error in #{name}" if do_raise
220
+ # And return a message as result. Nil is valid response.
221
+ return { success: true }, 'my_lib/events/success_event'
147
222
 
148
- # Do work Here...
149
- # And return 0 or more messages as result. Nil is valid response.
150
- return { kind: "#{name}_result", input: request }
223
+ # Optionally just return the message w/o a tagged kind
224
+ #return { success: true }
151
225
  end
152
226
 
153
227
  end
154
228
 
155
229
  # Create a new builder for this serf app.
156
- builder = Serf::Builder.new do
157
- # Include some middleware
158
- use Serf::Middleware::Masherize
159
- use Serf::Middleware::UuidTagger
160
- #use Serf::Middleware::GirlFridayAsync
161
-
162
- # Create response and error channels for the handler result messages.
163
- response_channel MyChannel.new my_logger
164
- error_channel MyChannel.new my_logger, true
165
-
166
- # We pass in a logger to our Serf code: Serfer and Runners.
167
- logger my_logger
168
-
169
- # Here, we define a route.
170
- # We are matching the kind for 'my_message', and we have the MyPolicy
171
- # to filter for this route.
172
- match 'my_message'
173
- policy MyPolicy
174
- run MyOverloadedCommand, name: 'my_message_command'
175
-
176
- match 'other_message'
177
- run MyOverloadedCommand, name: 'raises_error', raises: true
178
- run MyOverloadedCommand, name: 'good_other_handler'
179
-
180
- match /^events\/.*$/
181
- run MyOverloadedCommand, name: 'regexp_matched_command'
182
- end
183
- app = builder.to_app
184
-
185
- # This will submit a 'my_message' message (as a hash) to the Serf App.
186
- # NOTE: We should get an error message pushed to the error channel
187
- # because no 'data' field was put in my_message as required
188
- # And the Result should have a CaughtExceptionEvent.
189
- my_logger.info 'Call 1: Start'
190
- results = app.call(
191
- message: {
192
- kind: 'my_message'
193
- },
194
- context: nil)
195
- my_logger.info "Call 1: #{results.size} #{results.to_json}"
230
+ app = Serf::Builder.new(
231
+ interactor: MyInteractor.new,
232
+ policy_chain: [
233
+ MyPolicy.new
234
+ ]).to_app
235
+
236
+ # This will submit a 'my_message' message (as a hash) to Serfer.
237
+ # Missing data field will raise an error within the interactor, which
238
+ # will be caught by the serfer.
239
+ results = app.call nil
240
+ my_logger.info "Call 1: #{results.to_json}"
196
241
 
197
242
  # Here is good result
198
- my_logger.info 'Call 2: Start'
199
243
  results = app.call(
200
- message: {
201
- kind: 'my_message',
202
- data: '2'
244
+ headers: {
245
+ user: 'user_info_1'
203
246
  },
204
- context: nil)
205
- my_logger.info "Call 2: #{results.size} #{results.to_json}"
206
-
207
- # We should get two event messages in the results because we
208
- # mounted two commands to the other_message kind.
209
- my_logger.info 'Call 3: Start'
210
- results = app.call(
211
247
  message: {
212
- kind: 'other_message',
213
- data: '3'
214
- },
215
- context: nil)
216
- my_logger.info "Call 3: #{results.size} #{results.to_json}"
248
+ })
249
+ my_logger.info "Call 2: #{results.to_json}"
217
250
 
218
- # This will match a regexp call
219
- my_logger.info 'Call 4: Start'
251
+ # Here get an error that was raised from the interactor
220
252
  results = app.call(
221
- message: {
222
- kind: 'events/my_event',
223
- data: '4'
253
+ headers: {
254
+ user: 'user_info_1'
224
255
  },
225
- context: nil)
226
- my_logger.info "Call 4: #{results.size} #{results.to_json}"
227
-
228
- begin
229
- # Here, we're going to submit a message that we don't handle.
230
- # By default, an exception will be raised.
231
- my_logger.info 'Call 5: Start'
232
- app.call(
233
- message: {
234
- kind: 'unhandled_message_kind'
235
- },
236
- context: nil)
237
- my_logger.fatal 'OOOPS: Should not get here'
238
- rescue => e
239
- my_logger.info "Call 5: Caught in main: #{e.inspect}"
240
- end
241
-
256
+ message: {
257
+ raise_an_error: true
258
+ })
259
+ my_logger.info "Call 3: #{results.to_json}"
242
260
 
243
- Contributing to serf
244
- ====================
245
261
 
246
- * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
247
- * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
248
- * Fork the project
249
- * Start a feature/bugfix branch
250
- * Commit and push until you are happy with your contribution
251
- * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
252
- * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
262
+ Contributing
263
+ ============
253
264
 
265
+ 1. Fork it
266
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
267
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
268
+ 4. Push to the branch (`git push origin my-new-feature`)
269
+ 5. Create new Pull Request
254
270
 
255
271
  Copyright
256
272
  =========
data/Rakefile CHANGED
@@ -1,7 +1,8 @@
1
- # encoding: utf-8
2
-
1
+ #!/usr/bin/env rake
3
2
  require 'rubygems'
4
3
  require 'bundler'
4
+ require "bundler/gem_tasks"
5
+
5
6
  begin
6
7
  Bundler.setup(:default, :development)
7
8
  rescue Bundler::BundlerError => e
@@ -11,22 +12,6 @@ rescue Bundler::BundlerError => e
11
12
  end
12
13
  require 'rake'
13
14
 
14
- require 'jeweler'
15
- require './lib/serf/version.rb'
16
- Jeweler::Tasks.new do |gem|
17
- # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
18
- gem.name = "serf"
19
- gem.homepage = "http://github.com/byu/serf"
20
- gem.license = "Apache 2.0"
21
- gem.summary = %Q{Event-Driven SOA with CQRS}
22
- gem.description = %Q{Event-Driven SOA with CQRS}
23
- gem.email = "benjaminlyu@gmail.com"
24
- gem.authors = ["Benjamin Yu"]
25
- gem.version = Serf::Version::STRING
26
- # dependencies defined in Gemfile
27
- end
28
- Jeweler::RubygemsDotOrgTasks.new
29
-
30
15
  require 'rspec/core'
31
16
  require 'rspec/core/rake_task'
32
17
  RSpec::Core::RakeTask.new(:spec) do |spec|