batsir 0.1.0 → 0.3.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +9 -1
- data/CHANGES.md +54 -0
- data/Gemfile +7 -10
- data/README.md +49 -5
- data/Rakefile +23 -16
- data/batsir.gemspec +43 -15
- data/lib/batsir/acceptors/acceptor.rb +31 -5
- data/lib/batsir/acceptors/amqp_acceptor.rb +36 -8
- data/lib/batsir/amqp.rb +35 -7
- data/lib/batsir/amqp_consumer.rb +8 -0
- data/lib/batsir/compiler/stage_worker_compiler.rb +86 -0
- data/lib/batsir/config.rb +208 -24
- data/lib/batsir/dsl/conditional_notifier_declaration.rb +31 -0
- data/lib/batsir/dsl/dsl_mappings.rb +27 -2
- data/lib/batsir/errors.rb +18 -0
- data/lib/batsir/filter.rb +5 -0
- data/lib/batsir/log.rb +7 -0
- data/lib/batsir/logger.rb +37 -0
- data/lib/batsir/logo.rb +3 -8
- data/lib/batsir/notifiers/amqp_notifier.rb +14 -4
- data/lib/batsir/notifiers/conditional_notifier.rb +29 -0
- data/lib/batsir/notifiers/notifier.rb +6 -5
- data/lib/batsir/registry.rb +6 -2
- data/lib/batsir/stage.rb +9 -4
- data/lib/batsir/stage_worker.rb +3 -56
- data/lib/batsir/strategies/retry_strategy.rb +35 -0
- data/lib/batsir/strategies/strategy.rb +20 -0
- data/lib/batsir/transformers/field_transformer.rb +2 -3
- data/lib/batsir/transformers/json_input_transformer.rb +6 -2
- data/lib/batsir/transformers/json_output_transformer.rb +6 -2
- data/lib/batsir/transformers/transformer.rb +5 -1
- data/lib/batsir/version.rb +10 -0
- data/lib/batsir.rb +31 -13
- data/spec/batsir/acceptors/acceptor_spec.rb +7 -78
- data/spec/batsir/acceptors/amqp_acceptor_spec.rb +55 -66
- data/spec/batsir/acceptors/shared_examples.rb +102 -0
- data/spec/batsir/amqp_spec.rb +58 -0
- data/spec/batsir/chain_spec.rb +4 -4
- data/spec/batsir/config_spec.rb +97 -0
- data/spec/batsir/dsl/chain_mapping_spec.rb +5 -6
- data/spec/batsir/dsl/conditional_notifier_mapping_spec.rb +80 -0
- data/spec/batsir/dsl/stage_mapping_spec.rb +38 -20
- data/spec/batsir/filter_queue_spec.rb +9 -15
- data/spec/batsir/filter_spec.rb +4 -5
- data/spec/batsir/log_spec.rb +10 -0
- data/spec/batsir/logger_spec.rb +46 -0
- data/spec/batsir/notifiers/amqp_notifier_spec.rb +43 -22
- data/spec/batsir/notifiers/conditional_notifier_spec.rb +62 -0
- data/spec/batsir/notifiers/notifier_spec.rb +4 -66
- data/spec/batsir/notifiers/shared_examples.rb +100 -0
- data/spec/batsir/registry_spec.rb +48 -0
- data/spec/batsir/stage_spec.rb +91 -85
- data/spec/batsir/stage_worker_spec.rb +13 -13
- data/spec/batsir/strategies/retry_strategy_spec.rb +58 -0
- data/spec/batsir/strategies/strategy_spec.rb +28 -0
- data/spec/batsir/support/bunny_mocks.rb +78 -5
- data/spec/batsir/transformers/field_transformer_spec.rb +22 -22
- data/spec/batsir/transformers/json_input_transformer_spec.rb +8 -3
- data/spec/batsir/transformers/json_output_transformer_spec.rb +2 -2
- data/spec/batsir/transformers/transformer_spec.rb +18 -4
- data/spec/spec_helper.rb +6 -2
- metadata +78 -23
- data/VERSION +0 -1
data/.travis.yml
CHANGED
data/CHANGES.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
0.3.7
|
2
|
+
-----------
|
3
|
+
- AMQP queues are now durable by default.
|
4
|
+
This prevents queued messages getting lost when batsir is restarted (and the last consumer disconnects). It can be configured by setting 'Batsir::Config.amqp_durable'.
|
5
|
+
- Now requires bunny 0.10.7
|
6
|
+
|
7
|
+
|
8
|
+
0.3.6
|
9
|
+
-----------
|
10
|
+
- Fixes bug in conditional notifier
|
11
|
+
- Constrained Celluloid version to 0.14.x, until we can support 0.15.x and above
|
12
|
+
|
13
|
+
|
14
|
+
0.3.5
|
15
|
+
-----------
|
16
|
+
- NOTICE: This version removes sidekiq/celluloid gem contraints. Be sure to set these accordingly in your own project's Gemfile!
|
17
|
+
|
18
|
+
|
19
|
+
0.3.4
|
20
|
+
-----------
|
21
|
+
- Fixed issue when using bunny 0.9.0.pre9. Bunny::Session#start now returns ifself instead of its channel.
|
22
|
+
|
23
|
+
|
24
|
+
0.3.3
|
25
|
+
-----------
|
26
|
+
- Bunny :heartbeat option is now explicitly set. It defaults to 0; the original AMQP 0.8 setting.
|
27
|
+
|
28
|
+
|
29
|
+
0.3.2
|
30
|
+
-----------
|
31
|
+
- Filters can now be passed initialisation options
|
32
|
+
|
33
|
+
|
34
|
+
0.3.1
|
35
|
+
-----------
|
36
|
+
- Renamed config variable 'connection_pool_size' to a more apt 'amqp_pool_size'
|
37
|
+
|
38
|
+
|
39
|
+
0.3.0
|
40
|
+
-----------
|
41
|
+
- AMQPAcceptor and AMQPNotifier classes now only support Bunny 0.9 and up.
|
42
|
+
This fixes a bug that occurred when talking to an AMQP 0.9 server with a Bunny 0.8 client.
|
43
|
+
High message rates would, at some point, cause the server to reject all messages.
|
44
|
+
|
45
|
+
|
46
|
+
0.2.1
|
47
|
+
-----------
|
48
|
+
- Notifiers will not modify the message
|
49
|
+
- FieldTransformers now always return message hashes with strings for keys
|
50
|
+
|
51
|
+
|
52
|
+
0.2.0
|
53
|
+
-----------
|
54
|
+
- first production-ready code
|
data/Gemfile
CHANGED
@@ -1,17 +1,14 @@
|
|
1
|
-
source "
|
2
|
-
# Add dependencies required to use your gem here.
|
3
|
-
# Example:
|
4
|
-
# gem "activesupport", ">= 2.3.5"
|
1
|
+
source "https://rubygems.org"
|
5
2
|
|
6
|
-
# Add dependencies to develop your gem here.
|
7
|
-
# Include everything needed to run rake, tests, features, etc.
|
8
3
|
gem "bundler", "> 1.0.0"
|
9
4
|
gem "jeweler"
|
10
|
-
gem "
|
11
|
-
gem "
|
12
|
-
gem "
|
13
|
-
gem "
|
5
|
+
gem "rdoc"
|
6
|
+
gem "blockenspiel", ">= 0.4.3"
|
7
|
+
gem "celluloid", "~> 0.14.1"
|
8
|
+
gem "sidekiq", ">= 2.5.4"
|
9
|
+
gem "bunny", :github => "ruby-amqp/bunny", :tag => "0.10.7"
|
14
10
|
gem "json"
|
11
|
+
gem "log4r"
|
15
12
|
#gem "hot_bunnies", :git => "https://github.com/ruby-amqp/hot_bunnies.git"
|
16
13
|
|
17
14
|
group :development do
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/batsir.png)](http://badge.fury.io/rb/batsir)
|
2
|
+
[![Code Climate](https://codeclimate.com/github/jwkoelewijn/batsir.png)](https://codeclimate.com/github/jwkoelewijn/batsir)
|
1
3
|
[![Build Status](https://secure.travis-ci.org/jwkoelewijn/batsir.png?branch=master)](http://travis-ci.org/jwkoelewijn/batsir)
|
2
4
|
|
3
|
-
|
4
5
|
![Batsir Logo](/jwkoelewijn/batsir/raw/master/batsir.png)
|
5
6
|
|
6
7
|
# Batsir
|
@@ -43,27 +44,70 @@ Batsir.create_and_start do
|
|
43
44
|
end
|
44
45
|
```
|
45
46
|
|
46
|
-
This example creates 2 stages, 'stage 1' and 'stage 2'. The first stage creates and AMQPAcceptor,
|
47
|
+
This example creates 2 stages, 'stage 1' and 'stage 2'. The first stage creates and AMQPAcceptor,
|
47
48
|
that will connect to a AMQP Broker on localhost and will listen for messages on the 'some_queue' queue.
|
48
49
|
When a message is received, the message will be offered to the SumFilter first. The result of the
|
49
50
|
SumFilter is then sent to the #execute method of the AverageFilter. The result of this filter will
|
50
|
-
|
51
|
+
then be sent as an AMQP message on the 'queue_2' queue.
|
51
52
|
|
52
53
|
The inbound AMQPAcceptor of the second stage will then receive the message and its filters will be
|
53
54
|
invoked (the PrintFilter in this example).
|
54
55
|
|
56
|
+
# Conditional Notifiers
|
57
|
+
|
58
|
+
It is possible to create conditional notifiers. These accept a list of regular Notifiers which will
|
59
|
+
send a message only if the provided condition evaluates to true. The condition is given as a String,
|
60
|
+
which is evaluated in the context of a Proc at runtime. This Proc is always supplied with a 'message'
|
61
|
+
parameter, which is available when the condition is evaluated.
|
62
|
+
|
63
|
+
## Example of Conditional Notifier
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
Batsir.create_and_start do
|
67
|
+
stage "stage 1" do
|
68
|
+
inbound do
|
69
|
+
acceptor AMQPAcceptor, :queue => 'some_queue', :host => 'localhost'
|
70
|
+
end
|
71
|
+
filter SumFilter
|
72
|
+
filter AverageFilter
|
73
|
+
outbound do
|
74
|
+
conditional do
|
75
|
+
notify_if "message.to_i > 2", AMQPNotifier, :queue => 'gt_2'
|
76
|
+
notify_if "message.to_i < 2", AMQPNotifier, :queue => 'lt_3'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
stage "stage 2" do
|
82
|
+
inbound do
|
83
|
+
acceptor AMQPAcceptor, :queue => 'gt_2'
|
84
|
+
end
|
85
|
+
filter PrintFilter
|
86
|
+
end
|
87
|
+
|
88
|
+
stage "stage 3" do
|
89
|
+
inbound do
|
90
|
+
acceptor AMQPAcceptor, :queue => 'lt_3'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
```
|
95
|
+
|
96
|
+
In this example the message is sent to queue 'gt_2' if the integer value of the message is greater than 2,
|
97
|
+
and to queue 'lt_2' when the integer value of the message is less than 2.
|
98
|
+
|
55
99
|
# Sidekiq & Celluloid
|
56
100
|
Batsir acts as both a Sidekiq server and client at the same time. When Batsir#create_and_start is invoked,
|
57
101
|
Batsir will create Sidekiq workers on the fly, with instantiated filters on the workers. These workers will
|
58
102
|
be deployed in the Sidekiq server, so that they will be available for processing. The workers also register
|
59
103
|
themselves in a registry, where they can be requested using the stage name.
|
60
104
|
|
61
|
-
The inbound acceptors will listen as a Celluloid Actor on the client side of Sidekiq. When a message is
|
105
|
+
The inbound acceptors will listen as a Celluloid Actor on the client side of Sidekiq. When a message is
|
62
106
|
received, it will look up the corresponding StageWorker in the registry and it will invoke the
|
63
107
|
StageWorker asynchronously using Sidekiq.
|
64
108
|
|
65
109
|
## Contributing to batsir
|
66
|
-
|
110
|
+
|
67
111
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
68
112
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
69
113
|
* Fork the project
|
data/Rakefile
CHANGED
@@ -9,28 +9,36 @@ rescue Bundler::BundlerError => e
|
|
9
9
|
$stderr.puts "Run `bundle install` to install missing gems"
|
10
10
|
exit e.status_code
|
11
11
|
end
|
12
|
-
require 'rake'
|
13
12
|
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
14
|
+
|
15
|
+
require 'rake'
|
14
16
|
require 'jeweler'
|
17
|
+
require 'batsir/version'
|
18
|
+
|
19
|
+
version = Batsir::VERSION
|
20
|
+
|
15
21
|
Jeweler::Tasks.new do |gem|
|
16
22
|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
23
|
gem.name = "batsir"
|
24
|
+
gem.version = version
|
18
25
|
gem.homepage = "http://github.com/jwkoelewijn/batsir"
|
19
26
|
gem.license = "MIT"
|
20
27
|
gem.summary = %Q{Batsir is an execution platform for stage based operation queue execution}
|
21
|
-
gem.description = %Q{Batsir uses so called stages to define operation queues. These operation
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
gem.description = %Q{Batsir uses so called stages to define operation queues. These operation queues
|
29
|
+
consist of several operations that will be executed one after the other. Each stage
|
30
|
+
is defined by its name and the queue on which it will listen. Once a message is received
|
31
|
+
on the queue, it is dispatched to a worker in a seperate thread that will pass the message
|
32
|
+
to each operation in the operation queue.
|
33
|
+
Operation queues can have 4 different operations, 1 common operation type, and 3 special
|
34
|
+
purpose operations: retrieval operations (which are always executed before all other operations),
|
35
|
+
persistence operations (which are always executed after the common operations, but before the
|
36
|
+
notification operations) and notification operations (which will always be executed last)
|
37
|
+
This makes it possible to create chains of stages to perform tasks that depend on each
|
38
|
+
other, but otherwise have a low coupling}
|
32
39
|
gem.email = "jwkoelewijn@gmail.com"
|
33
|
-
gem.authors = ["J.W. Koelewijn"]
|
40
|
+
gem.authors = ["J.W. Koelewijn", "Bram de Vries"]
|
41
|
+
gem.extra_rdoc_files << "CHANGES.md"
|
34
42
|
# dependencies defined in Gemfile
|
35
43
|
end
|
36
44
|
Jeweler::RubygemsDotOrgTasks.new
|
@@ -44,12 +52,11 @@ end
|
|
44
52
|
|
45
53
|
task :default => :spec
|
46
54
|
|
47
|
-
require '
|
55
|
+
require 'rdoc/task'
|
48
56
|
Rake::RDocTask.new do |rdoc|
|
49
|
-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
50
|
-
|
51
57
|
rdoc.rdoc_dir = 'rdoc'
|
52
58
|
rdoc.title = "batsir #{version}"
|
53
59
|
rdoc.rdoc_files.include('README*')
|
60
|
+
rdoc.rdoc_files.include('CHANGES*')
|
54
61
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
55
62
|
end
|
data/batsir.gemspec
CHANGED
@@ -5,14 +5,15 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "batsir"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.7"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = ["J.W. Koelewijn"]
|
12
|
-
s.date = "
|
13
|
-
s.description = "Batsir uses so called stages to define operation queues. These operation
|
11
|
+
s.authors = ["J.W. Koelewijn", "Bram de Vries"]
|
12
|
+
s.date = "2013-10-24"
|
13
|
+
s.description = "Batsir uses so called stages to define operation queues. These operation queues\n consist of several operations that will be executed one after the other. Each stage\n is defined by its name and the queue on which it will listen. Once a message is received\n on the queue, it is dispatched to a worker in a seperate thread that will pass the message\n to each operation in the operation queue.\n Operation queues can have 4 different operations, 1 common operation type, and 3 special\n purpose operations: retrieval operations (which are always executed before all other operations),\n persistence operations (which are always executed after the common operations, but before the\n notification operations) and notification operations (which will always be executed last)\n This makes it possible to create chains of stages to perform tasks that depend on each\n other, but otherwise have a low coupling"
|
14
14
|
s.email = "jwkoelewijn@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
16
|
+
"CHANGES.md",
|
16
17
|
"LICENSE.txt",
|
17
18
|
"README.md"
|
18
19
|
]
|
@@ -20,43 +21,64 @@ Gem::Specification.new do |s|
|
|
20
21
|
".document",
|
21
22
|
".rspec",
|
22
23
|
".travis.yml",
|
24
|
+
"CHANGES.md",
|
23
25
|
"Gemfile",
|
24
26
|
"LICENSE.txt",
|
25
27
|
"README.md",
|
26
28
|
"Rakefile",
|
27
|
-
"VERSION",
|
28
29
|
"batsir.gemspec",
|
29
30
|
"batsir.png",
|
30
31
|
"lib/batsir.rb",
|
31
32
|
"lib/batsir/acceptors/acceptor.rb",
|
32
33
|
"lib/batsir/acceptors/amqp_acceptor.rb",
|
33
34
|
"lib/batsir/amqp.rb",
|
35
|
+
"lib/batsir/amqp_consumer.rb",
|
34
36
|
"lib/batsir/chain.rb",
|
37
|
+
"lib/batsir/compiler/stage_worker_compiler.rb",
|
35
38
|
"lib/batsir/config.rb",
|
39
|
+
"lib/batsir/dsl/conditional_notifier_declaration.rb",
|
36
40
|
"lib/batsir/dsl/dsl_mappings.rb",
|
41
|
+
"lib/batsir/errors.rb",
|
37
42
|
"lib/batsir/filter.rb",
|
38
43
|
"lib/batsir/filter_queue.rb",
|
44
|
+
"lib/batsir/log.rb",
|
45
|
+
"lib/batsir/logger.rb",
|
39
46
|
"lib/batsir/logo.rb",
|
40
47
|
"lib/batsir/notifiers/amqp_notifier.rb",
|
48
|
+
"lib/batsir/notifiers/conditional_notifier.rb",
|
41
49
|
"lib/batsir/notifiers/notifier.rb",
|
42
50
|
"lib/batsir/registry.rb",
|
43
51
|
"lib/batsir/stage.rb",
|
44
52
|
"lib/batsir/stage_worker.rb",
|
53
|
+
"lib/batsir/strategies/retry_strategy.rb",
|
54
|
+
"lib/batsir/strategies/strategy.rb",
|
45
55
|
"lib/batsir/transformers/field_transformer.rb",
|
46
56
|
"lib/batsir/transformers/json_input_transformer.rb",
|
47
57
|
"lib/batsir/transformers/json_output_transformer.rb",
|
48
58
|
"lib/batsir/transformers/transformer.rb",
|
59
|
+
"lib/batsir/version.rb",
|
49
60
|
"spec/batsir/acceptors/acceptor_spec.rb",
|
50
61
|
"spec/batsir/acceptors/amqp_acceptor_spec.rb",
|
62
|
+
"spec/batsir/acceptors/shared_examples.rb",
|
63
|
+
"spec/batsir/amqp_spec.rb",
|
51
64
|
"spec/batsir/chain_spec.rb",
|
65
|
+
"spec/batsir/config_spec.rb",
|
52
66
|
"spec/batsir/dsl/chain_mapping_spec.rb",
|
67
|
+
"spec/batsir/dsl/conditional_notifier_mapping_spec.rb",
|
53
68
|
"spec/batsir/dsl/stage_mapping_spec.rb",
|
54
69
|
"spec/batsir/filter_queue_spec.rb",
|
55
70
|
"spec/batsir/filter_spec.rb",
|
71
|
+
"spec/batsir/log_spec.rb",
|
72
|
+
"spec/batsir/logger_spec.rb",
|
56
73
|
"spec/batsir/notifiers/amqp_notifier_spec.rb",
|
74
|
+
"spec/batsir/notifiers/conditional_notifier_spec.rb",
|
57
75
|
"spec/batsir/notifiers/notifier_spec.rb",
|
76
|
+
"spec/batsir/notifiers/shared_examples.rb",
|
77
|
+
"spec/batsir/registry_spec.rb",
|
58
78
|
"spec/batsir/stage_spec.rb",
|
59
79
|
"spec/batsir/stage_worker_spec.rb",
|
80
|
+
"spec/batsir/strategies/retry_strategy_spec.rb",
|
81
|
+
"spec/batsir/strategies/strategy_spec.rb",
|
60
82
|
"spec/batsir/support/bunny_mocks.rb",
|
61
83
|
"spec/batsir/support/mock_filters.rb",
|
62
84
|
"spec/batsir/transformers/field_transformer_spec.rb",
|
@@ -68,7 +90,7 @@ Gem::Specification.new do |s|
|
|
68
90
|
s.homepage = "http://github.com/jwkoelewijn/batsir"
|
69
91
|
s.licenses = ["MIT"]
|
70
92
|
s.require_paths = ["lib"]
|
71
|
-
s.rubygems_version = "1.8.
|
93
|
+
s.rubygems_version = "1.8.25"
|
72
94
|
s.summary = "Batsir is an execution platform for stage based operation queue execution"
|
73
95
|
|
74
96
|
if s.respond_to? :specification_version then
|
@@ -77,28 +99,34 @@ Gem::Specification.new do |s|
|
|
77
99
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
78
100
|
s.add_runtime_dependency(%q<bundler>, ["> 1.0.0"])
|
79
101
|
s.add_runtime_dependency(%q<jeweler>, [">= 0"])
|
80
|
-
s.add_runtime_dependency(%q<
|
81
|
-
s.add_runtime_dependency(%q<
|
82
|
-
s.add_runtime_dependency(%q<
|
102
|
+
s.add_runtime_dependency(%q<rdoc>, [">= 0"])
|
103
|
+
s.add_runtime_dependency(%q<blockenspiel>, [">= 0.4.3"])
|
104
|
+
s.add_runtime_dependency(%q<celluloid>, ["~> 0.14.1"])
|
105
|
+
s.add_runtime_dependency(%q<sidekiq>, [">= 2.5.4"])
|
83
106
|
s.add_runtime_dependency(%q<bunny>, [">= 0"])
|
84
107
|
s.add_runtime_dependency(%q<json>, [">= 0"])
|
108
|
+
s.add_runtime_dependency(%q<log4r>, [">= 0"])
|
85
109
|
else
|
86
110
|
s.add_dependency(%q<bundler>, ["> 1.0.0"])
|
87
111
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
88
|
-
s.add_dependency(%q<
|
89
|
-
s.add_dependency(%q<
|
90
|
-
s.add_dependency(%q<
|
112
|
+
s.add_dependency(%q<rdoc>, [">= 0"])
|
113
|
+
s.add_dependency(%q<blockenspiel>, [">= 0.4.3"])
|
114
|
+
s.add_dependency(%q<celluloid>, ["~> 0.14.1"])
|
115
|
+
s.add_dependency(%q<sidekiq>, [">= 2.5.4"])
|
91
116
|
s.add_dependency(%q<bunny>, [">= 0"])
|
92
117
|
s.add_dependency(%q<json>, [">= 0"])
|
118
|
+
s.add_dependency(%q<log4r>, [">= 0"])
|
93
119
|
end
|
94
120
|
else
|
95
121
|
s.add_dependency(%q<bundler>, ["> 1.0.0"])
|
96
122
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
97
|
-
s.add_dependency(%q<
|
98
|
-
s.add_dependency(%q<
|
99
|
-
s.add_dependency(%q<
|
123
|
+
s.add_dependency(%q<rdoc>, [">= 0"])
|
124
|
+
s.add_dependency(%q<blockenspiel>, [">= 0.4.3"])
|
125
|
+
s.add_dependency(%q<celluloid>, ["~> 0.14.1"])
|
126
|
+
s.add_dependency(%q<sidekiq>, [">= 2.5.4"])
|
100
127
|
s.add_dependency(%q<bunny>, [">= 0"])
|
101
128
|
s.add_dependency(%q<json>, [">= 0"])
|
129
|
+
s.add_dependency(%q<log4r>, [">= 0"])
|
102
130
|
end
|
103
131
|
end
|
104
132
|
|
@@ -18,27 +18,53 @@ module Batsir
|
|
18
18
|
@transformer_queue << transformer
|
19
19
|
end
|
20
20
|
|
21
|
+
#
|
21
22
|
# This method is called automatically when the stage is
|
22
23
|
# started, it is here that you set up the accepting
|
23
24
|
# logic. Make sure that somewhere within this logic
|
24
25
|
# the #start_filter_chain(msg) is called to start
|
25
|
-
# actual processing
|
26
|
+
# actual processing.
|
26
27
|
#
|
27
28
|
# Note that this method will be invoked asynchronously
|
28
29
|
# using the Celluloid actor semantics.
|
30
|
+
#
|
29
31
|
def start
|
30
|
-
|
32
|
+
raise NotImplementedError.new
|
31
33
|
end
|
32
34
|
|
35
|
+
#
|
33
36
|
# When a message is accepted by an Acceptor, this method
|
34
37
|
# should be invoked with the received payload to start
|
35
|
-
# processing of the filter chain
|
38
|
+
# processing of the filter chain.
|
39
|
+
#
|
36
40
|
def start_filter_chain(message)
|
37
41
|
klazz = Batsir::Registry.get(stage_name)
|
42
|
+
message = transform(message)
|
43
|
+
klazz.perform_async(message) if klazz
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Call each of the transformers in the transformer_queue
|
48
|
+
# on the message, in order
|
49
|
+
#
|
50
|
+
def transform(message)
|
38
51
|
transformer_queue.each do |transformer|
|
39
|
-
|
52
|
+
begin
|
53
|
+
message = transformer.transform(message)
|
54
|
+
rescue Batsir::Errors::TransformError => e
|
55
|
+
message = process_message_error(message, e)
|
56
|
+
end
|
40
57
|
end
|
41
|
-
|
58
|
+
message
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# This method is called after an error is thrown.
|
63
|
+
# Can be overridden to implement error handling.
|
64
|
+
# Returns a message
|
65
|
+
#
|
66
|
+
def process_message_error(message, error)
|
67
|
+
message
|
42
68
|
end
|
43
69
|
end
|
44
70
|
end
|
@@ -4,16 +4,44 @@ module Batsir
|
|
4
4
|
module Acceptors
|
5
5
|
class AMQPAcceptor < Acceptor
|
6
6
|
include Batsir::AMQP
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
7
|
+
include Batsir::Log
|
8
|
+
|
9
|
+
attr_reader :consumer
|
10
|
+
attr_writer :consumer_source
|
11
|
+
|
12
|
+
def initialize(options={})
|
13
|
+
super
|
14
|
+
@bunny = Bunny.new(bunny_options).start
|
15
|
+
@channel = @bunny.channel
|
16
|
+
@q = @bunny.queue( queue, :durable => durable )
|
17
|
+
@x = @bunny.exchange( exchange )
|
18
|
+
@q.bind( @x, :routing_key => queue)
|
19
|
+
|
20
|
+
@consumer = consumer_source.call(self, @channel, @q)
|
21
|
+
@consumer.on_delivery() do |delivery_info, metadata, payload|
|
22
|
+
handle_delivery(payload)
|
15
23
|
end
|
16
24
|
end
|
25
|
+
|
26
|
+
def start
|
27
|
+
@q.subscribe_with(@consumer)
|
28
|
+
end
|
29
|
+
|
30
|
+
def handle_delivery(payload)
|
31
|
+
start_filter_chain(payload)
|
32
|
+
end
|
33
|
+
|
34
|
+
def process_message_error(message, error)
|
35
|
+
log.error error.message
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def consumer_source
|
42
|
+
@consumer_source ||= Batsir::AMQPConsumer.public_method(:new)
|
43
|
+
end
|
44
|
+
|
17
45
|
end
|
18
46
|
end
|
19
47
|
end
|
data/lib/batsir/amqp.rb
CHANGED
@@ -5,8 +5,10 @@ module Batsir
|
|
5
5
|
attr_accessor :port
|
6
6
|
attr_accessor :username
|
7
7
|
attr_accessor :password
|
8
|
+
attr_accessor :durable
|
8
9
|
attr_accessor :vhost
|
9
10
|
attr_accessor :exchange
|
11
|
+
attr_accessor :heartbeat
|
10
12
|
|
11
13
|
def bunny_options
|
12
14
|
{
|
@@ -14,32 +16,58 @@ module Batsir
|
|
14
16
|
:port => port,
|
15
17
|
:user => username,
|
16
18
|
:pass => password,
|
17
|
-
:vhost => vhost
|
19
|
+
:vhost => vhost,
|
20
|
+
:heartbeat => heartbeat
|
18
21
|
}
|
19
22
|
end
|
20
23
|
|
21
24
|
def host
|
22
|
-
@host
|
25
|
+
@host ||= Batsir::Config.fetch(:amqp_host, 'localhost')
|
23
26
|
end
|
24
27
|
|
25
28
|
def port
|
26
|
-
@port
|
29
|
+
@port ||= Batsir::Config.fetch(:amqp_port, 5672)
|
27
30
|
end
|
28
31
|
|
29
32
|
def username
|
30
|
-
@username
|
33
|
+
@username ||= Batsir::Config.fetch(:amqp_user, 'guest')
|
31
34
|
end
|
32
35
|
|
33
36
|
def password
|
34
|
-
@password
|
37
|
+
@password ||= Batsir::Config.fetch(:amqp_pass, 'guest')
|
35
38
|
end
|
36
39
|
|
37
40
|
def vhost
|
38
|
-
@vhost
|
41
|
+
@vhost ||= Batsir::Config.fetch(:amqp_vhost, '/')
|
39
42
|
end
|
40
43
|
|
41
44
|
def exchange
|
42
|
-
@exchange
|
45
|
+
@exchange ||= Batsir::Config.fetch(:amqp_exchange, 'amq.direct')
|
46
|
+
end
|
47
|
+
|
48
|
+
def heartbeat
|
49
|
+
@heartbeat ||= Batsir::Config.fetch(:amqp_heartbeat, 0) # default to AMQP 0.8 heartbeat setting
|
50
|
+
end
|
51
|
+
|
52
|
+
def bunny_pool_size
|
53
|
+
@bunny_pool_size ||= Batsir::Config.ampq_pool_size
|
54
|
+
end
|
55
|
+
|
56
|
+
def durable
|
57
|
+
@durable ||= Batsir::Config.fetch(:amqp_durable, true)
|
58
|
+
end
|
59
|
+
|
60
|
+
def bunny_pool_key
|
61
|
+
"bunny_pool_for_#{host}_#{port}_#{vhost}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def bunny_pool
|
65
|
+
@bunny_pool = Batsir::Registry.get(bunny_pool_key)
|
66
|
+
if !@bunny_pool
|
67
|
+
pool = ConnectionPool.new(:size => bunny_pool_size) { Bunny.new(bunny_options).start }
|
68
|
+
@bunny_pool = Batsir::Registry.register(bunny_pool_key, pool)
|
69
|
+
end
|
70
|
+
@bunny_pool
|
43
71
|
end
|
44
72
|
end
|
45
73
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Batsir
|
2
|
+
module Compiler
|
3
|
+
class StageWorkerCompiler
|
4
|
+
attr_accessor :stage
|
5
|
+
|
6
|
+
def initialize(stage)
|
7
|
+
@stage = stage
|
8
|
+
end
|
9
|
+
|
10
|
+
def compile
|
11
|
+
klazz_name = "#{stage.name.capitalize.gsub(' ','')}Worker"
|
12
|
+
code = <<-EOF
|
13
|
+
class #{klazz_name}
|
14
|
+
def self.stage_name
|
15
|
+
"#{stage.name}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@filter_queue = self.class.filter_queue
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.filter_queue
|
23
|
+
@filter_queue
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.initialize_filter_queue
|
27
|
+
@filter_queue = Batsir::FilterQueue.new
|
28
|
+
EOF
|
29
|
+
|
30
|
+
stage.filter_declarations.each do |filter_declaration|
|
31
|
+
code << <<-EOF
|
32
|
+
@filter_queue.add #{filter_declaration.filter.to_s}.new(#{filter_declaration.options.to_s})
|
33
|
+
EOF
|
34
|
+
end
|
35
|
+
|
36
|
+
stage.conditional_notifiers.each do |conditional_notifier_declaration|
|
37
|
+
conditional_notifier_declaration.compile(code, self)
|
38
|
+
end
|
39
|
+
|
40
|
+
stage.notifiers.each do |notifier, options_set|
|
41
|
+
options_set.each do |options|
|
42
|
+
code << <<-EOF
|
43
|
+
notifier = #{notifier.to_s}.new(#{options.to_s})
|
44
|
+
EOF
|
45
|
+
|
46
|
+
self.add_transformers_to_notifier("notifier", code)
|
47
|
+
|
48
|
+
self.add_notifier("notifier", code)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
code << <<-EOF
|
53
|
+
end
|
54
|
+
|
55
|
+
include Sidekiq::Worker
|
56
|
+
include Batsir::StageWorker
|
57
|
+
end
|
58
|
+
|
59
|
+
#{klazz_name}.sidekiq_options(:queue => Batsir::Config.sidekiq_queue)
|
60
|
+
#{klazz_name}
|
61
|
+
EOF
|
62
|
+
code
|
63
|
+
end
|
64
|
+
|
65
|
+
def add_transformers_to_notifier(notifier_name, code)
|
66
|
+
if stage.notifier_transformers.any?
|
67
|
+
stage.notifier_transformers.each do |transformer_declaration|
|
68
|
+
code << <<-EOF
|
69
|
+
#{notifier_name}.add_transformer #{transformer_declaration.transformer}.new(#{transformer_declaration.options.to_s})
|
70
|
+
EOF
|
71
|
+
end
|
72
|
+
else
|
73
|
+
code << <<-EOF
|
74
|
+
#{notifier_name}.add_transformer Batsir::Transformers::JSONOutputTransformer.new
|
75
|
+
EOF
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def add_notifier(notifier_name, code)
|
80
|
+
code << <<-EOF
|
81
|
+
@filter_queue.add_notifier #{notifier_name}
|
82
|
+
EOF
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|