serf 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,49 +0,0 @@
1
- require 'serf/util/options_extraction'
2
-
3
- module Serf
4
- module Routing
5
-
6
- ##
7
- # An endpoint is the description of how to build a Unit of Work
8
- # for a given matched message. It builds an instance that
9
- # responds to the `call` method that will actually execute the work.
10
- # Units of work is built on every received message with the request,
11
- # given arguments, options (merged with serf infrastructure options)
12
- # and given block.
13
- #
14
- class Endpoint
15
- include Serf::Util::OptionsExtraction
16
-
17
- def initialize(connect, handler_factory, *args, &block)
18
- # If we want to connect serf options, then we try to extract
19
- # any possible options from the args list. If a hash exists at the
20
- # end of the args list, then we'll merge into it. Otherwise a new hash
21
- # will be added on.
22
- extract_options! args if @connect = connect
23
-
24
- @handler_factory= handler_factory
25
- @args = args
26
- @block = block
27
- end
28
-
29
- ##
30
- # Builds a Unit of Work object.
31
- #
32
- def build(env, serf_options={})
33
- # If we are connecting serf options, then we need to pass these
34
- # options on to the builder.
35
- if @connect
36
- @handler_factory.build(
37
- env.dup,
38
- *@args,
39
- options.merge(serf_options),
40
- &@block)
41
- else
42
- @handler_factory.build env.dup, *@args, &@block
43
- end
44
- end
45
-
46
- end
47
-
48
- end
49
- end
@@ -1,66 +0,0 @@
1
- require 'serf/util/regexp_matcher'
2
-
3
- module Serf
4
- module Routing
5
-
6
- ##
7
- # EndpointRegistry returns list of Endpoints to execute that match
8
- # criteria based on the Endpoints' associated 'matcher' object
9
- # with the input of the ENV Hash (passed to match).
10
- #
11
- class Registry
12
-
13
- def initialize(options={})
14
- @endpoints = {}
15
- @matchers = []
16
- @regexp_matcher_factory = options.fetch(:regexp_matcher_factory) {
17
- ::Serf::Util::RegexpMatcher
18
- }
19
- end
20
-
21
- ##
22
- # Connects a matcher (String or an Object implementing ===) to endpoints.
23
- #
24
- def add(matcher, endpoints)
25
- # Maybe we have an non-String matcher. Handle the Regexp case.
26
- # We only keep track of matchers if it isn't a string because
27
- # string matchers are just pulled out of endpoints by key lookup.
28
- matcher = @regexp_matcher_factory.build matcher if matcher.kind_of? Regexp
29
- @matchers << matcher unless matcher.is_a? String
30
-
31
- # We add the (matcher+endpoint) into our endpoints
32
- @endpoints[matcher] ||= []
33
- @endpoints[matcher].concat endpoints
34
- end
35
-
36
- ##
37
- # @param [Hash] env The input message environment to match for endpoints.
38
- # @return [Array] List of endpoints that matched.
39
- #
40
- def match(env={})
41
- kind = env[:kind]
42
- endpoints = []
43
- endpoints.concat @endpoints.fetch(kind) { [] }
44
- @matchers.each do |matcher|
45
- endpoints.concat @endpoints[matcher] if matcher === env
46
- end
47
- return endpoints
48
- end
49
-
50
- ##
51
- # @return [Integer] Number of matchers this EndpointsMap tracks.
52
- #
53
- def size
54
- return @endpoints.size
55
- end
56
-
57
- ##
58
- # Default factory method.
59
- #
60
- def self.build(options={})
61
- self.new options
62
- end
63
- end
64
-
65
- end
66
- end
@@ -1,52 +0,0 @@
1
- require 'serf/runners/helper'
2
- require 'serf/util/error_handling'
3
-
4
- module Serf
5
- module Runners
6
-
7
- ##
8
- # Direct runner drives the execution of a handler for given messages.
9
- # This class deals with error handling and pushing handler results
10
- # to proper error or results channels.
11
- #
12
- # NOTES:
13
- # * Results returned from handlers are pushed to response channel.
14
- # * Errors raised by handlers are pushed to error channel, not response.
15
- #
16
- class Direct
17
- include Serf::Util::ErrorHandling
18
- include Serf::Runners::Helper
19
-
20
- def initialize(*args)
21
- extract_options! args
22
- opts! :response_channel
23
- end
24
-
25
- def call(handlers, context)
26
- results = []
27
- handlers.each do |handler|
28
- ok, run_result = with_error_handling(context) do
29
- handler.call
30
- end
31
- run_result = run_result.is_a?(Hash) ? [run_result] : Array(run_result)
32
-
33
- # We only post to the response channel if we didn't catch and error.
34
- # But we add both error and success results to the 'results' to
35
- # pass back to the caller of the runner. This may be a background
36
- # runner, which then the results are ignored. But it may have been
37
- # the Serfer, which means all results should go back to the user
38
- # as this was a foreground (synchronous) execution.
39
- results.concat run_result
40
- push_results run_result if ok
41
- end
42
- return results
43
- end
44
-
45
- def self.build(options={})
46
- self.new options
47
- end
48
-
49
- end
50
-
51
- end
52
- end
@@ -1,69 +0,0 @@
1
- require 'eventmachine'
2
-
3
- require 'serf/runners/direct'
4
- require 'serf/util/error_handling'
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 pushing to error channels because that may have
23
- # been the cause of the error.
24
- #
25
- class EventMachine
26
- include Serf::Util::ErrorHandling
27
-
28
- def initialize(*args)
29
- extract_options! args
30
-
31
- # Manditory: Need a runner because this class is just a wrapper.
32
- @runner = opts! :runner
33
-
34
- @evm = opts :event_machine, ::EventMachine
35
- @logger = opts :logger, ::Serf::Util::NullObject.new
36
- end
37
-
38
- def call(handlers, context)
39
- # This queues up each handler to be run separately.
40
- handlers.each do |handler|
41
- @evm.defer(proc do
42
- begin
43
- with_error_handling(context) do
44
- @runner.call [handler], context
45
- end
46
- rescue => e
47
- @logger.fatal(
48
- "EventMachineThread: #{e.inspect}\n\n#{e.backtrace.join("\n")}")
49
- end
50
- end)
51
- end
52
- return {
53
- kind: 'serf/messages/message_accepted_event',
54
- message: context
55
- }
56
- end
57
-
58
- def self.build(options={})
59
- options[:runner] = options.fetch(:runner) {
60
- factory = options[:runner_factory] || ::Serf::Runners::Direct
61
- factory.build options
62
- }
63
- self.new options
64
- end
65
-
66
- end
67
-
68
- end
69
- end
@@ -1,69 +0,0 @@
1
- require 'girl_friday'
2
-
3
- require 'serf/runners/helper'
4
- require 'serf/util/error_handling'
5
-
6
- module Serf
7
- module Runners
8
-
9
- ##
10
- #
11
- class GirlFriday
12
- include Serf::Util::ErrorHandling
13
- include Serf::Runners::Helper
14
-
15
- def initialize(*args)
16
- extract_options! args
17
-
18
- # Mandatory response channel.
19
- opts! :response_channel
20
-
21
- # Create our worker queue that will accept tasks (handler and context).
22
- # The worker is just a block that passes on the task to the
23
- # actual worker method.
24
- @queue = ::GirlFriday::WorkQueue.new(
25
- opts(:queue_name, :serf_runner),
26
- :size => opts(:queue_size, 1)) do |task|
27
- perform task
28
- end
29
- end
30
-
31
- def call(handlers, context)
32
- # Push each handler into the queue along with a copy of the context.
33
- handlers.each do |handler|
34
- @queue.push(
35
- handler: handler,
36
- context: context.dup)
37
- end
38
-
39
- # We got here, we succeeded pushing all the works.
40
- # Now we return our accepted event.
41
- return {
42
- kind: 'serf/messages/message_accepted_event',
43
- message: context
44
- }
45
- end
46
-
47
- ##
48
- # Builder method
49
- #
50
- def self.build(*args)
51
- self.new *args
52
- end
53
-
54
- ##
55
- # Actually drives the execution of individual handlers passed to job
56
- # queue.
57
- #
58
- def perform(task)
59
- ok, run_result = with_error_handling(task[:context]) do
60
- task[:handler].call
61
- end
62
- run_result = run_result.is_a?(Hash) ? [run_result] : Array(run_result)
63
- push_results run_result if ok
64
- end
65
-
66
- end
67
-
68
- end
69
- end
@@ -1,23 +0,0 @@
1
- module Serf
2
- module Runners
3
-
4
- module Helper
5
-
6
- ##
7
- # Loop over the results and push them to the response channel.
8
- # Any error in pushing individual messages will result in
9
- # a log event and an error channel event.
10
- def push_results(results)
11
- response_channel = opts! :response_channel
12
- results.each do |message|
13
- with_error_handling(message) do
14
- response_channel.push message
15
- end
16
- end
17
- return nil
18
- end
19
-
20
- end
21
-
22
- end
23
- end
@@ -1,18 +0,0 @@
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