activemessaging 0.7.1 → 0.8.1
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.
- data/README +7 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/activemessaging.gemspec +78 -78
- data/generators/processor/templates/broker.yml +49 -0
- data/init.rb +0 -2
- data/lib/activemessaging.rb +41 -43
- data/lib/activemessaging/adapter.rb +1 -2
- data/lib/activemessaging/adapters/amqp.rb +215 -0
- data/lib/activemessaging/adapters/asqs.rb +3 -3
- data/lib/activemessaging/adapters/beanstalk.rb +1 -1
- data/lib/activemessaging/adapters/stomp.rb +49 -13
- data/lib/activemessaging/adapters/synch.rb +94 -0
- data/lib/activemessaging/gateway.rb +11 -12
- data/lib/activemessaging/processor.rb +2 -3
- data/lib/activemessaging/railtie.rb +22 -0
- data/lib/activemessaging/trace_filter.rb +34 -34
- data/{tasks → lib/tasks}/start_consumers.rake +0 -0
- data/test/stomp_test.rb +25 -1
- metadata +34 -14
- data/lib/activemessaging/support.rb +0 -17
data/README
CHANGED
@@ -19,4 +19,10 @@ h1. Support
|
|
19
19
|
|
20
20
|
Best bet is the google groups mailing list:
|
21
21
|
|
22
|
-
http://groups.google.com/group/activemessaging-discuss
|
22
|
+
http://groups.google.com/group/activemessaging-discuss
|
23
|
+
|
24
|
+
h1. Fork Details
|
25
|
+
|
26
|
+
This fork adds the ability to specify a dead letter queue prefix so instead of all messages going to 1 dead letter queue, each message will go to a dead letter queue that is based on the deadLetterQueuePrefix configuration property and the originating queue.
|
27
|
+
|
28
|
+
For example, if you specific a deadLetterQueuePrefix of "DLQ." in your broker.yml and the originating queue is /queue/myqueue then the dead letter queue will be /queue/DLQ.myqueue
|
data/Rakefile
CHANGED
@@ -26,7 +26,7 @@ begin
|
|
26
26
|
# basic
|
27
27
|
gemspec.name = "activemessaging"
|
28
28
|
gemspec.summary = "Official activemessaging gem, now hosted on github.com/kookster. (kookster prefix temporary)"
|
29
|
-
gemspec.description = "ActiveMessaging is an attempt to bring the simplicity and elegance of rails development to the world of messaging. Messaging, (or event-driven architecture) is widely used for enterprise integration, with frameworks such as Java's JMS, and products such as ActiveMQ, Tibco, IBM MQSeries, etc."
|
29
|
+
gemspec.description = "ActiveMessaging is an attempt to bring the simplicity and elegance of rails development to the world of messaging. Messaging, (or event-driven architecture) is widely used for enterprise integration, with frameworks such as Java's JMS, and products such as ActiveMQ, Tibco, IBM MQSeries, etc. Now supporting Rails 3 as of version 0.8.0."
|
30
30
|
gemspec.email = "activemessaging-discuss@googlegroups.com"
|
31
31
|
gemspec.homepage = "http://github.com/kookster/activemessaging"
|
32
32
|
gemspec.authors = ["Jon Tirsen", "Andrew Kuklewicz", "Olle Jonsson", "Sylvain Perez", "Cliff Moon", 'Uwe Kubosch']
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.8.1
|
data/activemessaging.gemspec
CHANGED
@@ -1,107 +1,107 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{activemessaging}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.8.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jon Tirsen", "Andrew Kuklewicz", "Olle Jonsson", "Sylvain Perez", "Cliff Moon", "Uwe Kubosch"]
|
12
|
-
s.date = %q{
|
13
|
-
s.description = %q{ActiveMessaging is an attempt to bring the simplicity and elegance of rails development to the world of messaging. Messaging, (or event-driven architecture) is widely used for enterprise integration, with frameworks such as Java's JMS, and products such as ActiveMQ, Tibco, IBM MQSeries, etc.}
|
12
|
+
s.date = %q{2011-08-15}
|
13
|
+
s.description = %q{ActiveMessaging is an attempt to bring the simplicity and elegance of rails development to the world of messaging. Messaging, (or event-driven architecture) is widely used for enterprise integration, with frameworks such as Java's JMS, and products such as ActiveMQ, Tibco, IBM MQSeries, etc. Now supporting Rails 3 as of version 0.8.0.}
|
14
14
|
s.email = %q{activemessaging-discuss@googlegroups.com}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"README"
|
17
17
|
]
|
18
18
|
s.files = [
|
19
19
|
"README",
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
20
|
+
"Rakefile",
|
21
|
+
"VERSION",
|
22
|
+
"activemessaging.gemspec",
|
23
|
+
"generators/a13g_test_harness/a13g_test_harness_generator.rb",
|
24
|
+
"generators/a13g_test_harness/templates/active_messaging_test.rhtml",
|
25
|
+
"generators/a13g_test_harness/templates/active_messaging_test_controller.rb",
|
26
|
+
"generators/a13g_test_harness/templates/index.rhtml",
|
27
|
+
"generators/filter/USAGE",
|
28
|
+
"generators/filter/filter_generator.rb",
|
29
|
+
"generators/filter/templates/filter.rb",
|
30
|
+
"generators/filter/templates/filter_test.rb",
|
31
|
+
"generators/processor/USAGE",
|
32
|
+
"generators/processor/processor_generator.rb",
|
33
|
+
"generators/processor/templates/application.rb",
|
34
|
+
"generators/processor/templates/broker.yml",
|
35
|
+
"generators/processor/templates/jruby_poller",
|
36
|
+
"generators/processor/templates/messaging.rb",
|
37
|
+
"generators/processor/templates/poller",
|
38
|
+
"generators/processor/templates/poller.rb",
|
39
|
+
"generators/processor/templates/processor.rb",
|
40
|
+
"generators/processor/templates/processor_test.rb",
|
41
|
+
"generators/tracer/USAGE",
|
42
|
+
"generators/tracer/templates/controller.rb",
|
43
|
+
"generators/tracer/templates/helper.rb",
|
44
|
+
"generators/tracer/templates/index.rhtml",
|
45
|
+
"generators/tracer/templates/layout.rhtml",
|
46
|
+
"generators/tracer/templates/trace_processor.rb",
|
47
|
+
"generators/tracer/tracer_generator.rb",
|
48
|
+
"init.rb",
|
49
|
+
"lib/activemessaging.rb",
|
50
|
+
"lib/activemessaging/adapter.rb",
|
51
|
+
"lib/activemessaging/adapters/amqp.rb",
|
52
|
+
"lib/activemessaging/adapters/asqs.rb",
|
53
|
+
"lib/activemessaging/adapters/base.rb",
|
54
|
+
"lib/activemessaging/adapters/beanstalk.rb",
|
55
|
+
"lib/activemessaging/adapters/jms.rb",
|
56
|
+
"lib/activemessaging/adapters/reliable_msg.rb",
|
57
|
+
"lib/activemessaging/adapters/stomp.rb",
|
58
|
+
"lib/activemessaging/adapters/synch.rb",
|
59
|
+
"lib/activemessaging/adapters/test.rb",
|
60
|
+
"lib/activemessaging/adapters/wmq.rb",
|
61
|
+
"lib/activemessaging/base_message.rb",
|
62
|
+
"lib/activemessaging/filter.rb",
|
63
|
+
"lib/activemessaging/gateway.rb",
|
64
|
+
"lib/activemessaging/message_sender.rb",
|
65
|
+
"lib/activemessaging/named_base.rb",
|
66
|
+
"lib/activemessaging/processor.rb",
|
67
|
+
"lib/activemessaging/railtie.rb",
|
68
|
+
"lib/activemessaging/test_helper.rb",
|
69
|
+
"lib/activemessaging/trace_filter.rb",
|
70
|
+
"lib/tasks/start_consumers.rake",
|
71
|
+
"poller.rb",
|
72
|
+
"test/all_tests.rb",
|
73
|
+
"test/app/config/broker.yml",
|
74
|
+
"test/asqs_test.rb",
|
75
|
+
"test/config_test.rb",
|
76
|
+
"test/filter_test.rb",
|
77
|
+
"test/gateway_test.rb",
|
78
|
+
"test/jms_test.rb",
|
79
|
+
"test/reliable_msg_test.rb",
|
80
|
+
"test/stomp_test.rb",
|
81
|
+
"test/test_helper.rb",
|
82
|
+
"test/tracer_test.rb"
|
81
83
|
]
|
82
84
|
s.homepage = %q{http://github.com/kookster/activemessaging}
|
83
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
84
85
|
s.require_paths = ["lib"]
|
85
|
-
s.rubygems_version = %q{1.
|
86
|
+
s.rubygems_version = %q{1.4.2}
|
86
87
|
s.summary = %q{Official activemessaging gem, now hosted on github.com/kookster. (kookster prefix temporary)}
|
87
88
|
s.test_files = [
|
88
89
|
"test/all_tests.rb",
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
90
|
+
"test/asqs_test.rb",
|
91
|
+
"test/config_test.rb",
|
92
|
+
"test/filter_test.rb",
|
93
|
+
"test/gateway_test.rb",
|
94
|
+
"test/jms_test.rb",
|
95
|
+
"test/reliable_msg_test.rb",
|
96
|
+
"test/stomp_test.rb",
|
97
|
+
"test/test_helper.rb",
|
98
|
+
"test/tracer_test.rb"
|
98
99
|
]
|
99
100
|
|
100
101
|
if s.respond_to? :specification_version then
|
101
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
102
102
|
s.specification_version = 3
|
103
103
|
|
104
|
-
if Gem::Version.new(Gem::
|
104
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
105
105
|
s.add_runtime_dependency(%q<activesupport>, [">= 1.0.0"])
|
106
106
|
else
|
107
107
|
s.add_dependency(%q<activesupport>, [">= 1.0.0"])
|
@@ -27,6 +27,55 @@ development:
|
|
27
27
|
# If error still occurs after retryMax, send message to specified dead letter queue
|
28
28
|
# deadLetterQueue: '/queue/activemessaging/deadletter'
|
29
29
|
|
30
|
+
|
31
|
+
###########################
|
32
|
+
# AMQP Adapter Properties #
|
33
|
+
###########################
|
34
|
+
# adapter: amqp
|
35
|
+
|
36
|
+
# properties below are defaults for this adapter
|
37
|
+
# host: localhost
|
38
|
+
# port: 5672
|
39
|
+
# user: guest
|
40
|
+
# pass: guest
|
41
|
+
# vhost: /
|
42
|
+
# ssl: false
|
43
|
+
# ssl_verify: 1
|
44
|
+
# debug: 0
|
45
|
+
# queue_name: <autogenerated>
|
46
|
+
# queue_durable: false if queue_name is autogenerated, defaults to true otherwise
|
47
|
+
# queue_auto_delete: true if queue_name is autogenerated, defaults to false otherwise
|
48
|
+
# queue_exclusive: true if queue_name is autogenerated, defaults to true otherwise
|
49
|
+
|
50
|
+
# SSL:
|
51
|
+
|
52
|
+
# in order to use SSL you will need to use the following fork of the carrot project:
|
53
|
+
#
|
54
|
+
# http://github.com/rabbitt/carrot
|
55
|
+
#
|
56
|
+
# If your certificate is self signed, you will want to set ssl_verify to 0 which corresponds to
|
57
|
+
# OpenSSL::SSL::VERIFY_NONE. Otherwise, it defaults to 1 (OpenSSL::SSL::VERIFY_PEER).
|
58
|
+
|
59
|
+
# QUEUE_*:
|
60
|
+
|
61
|
+
# queue_name is the name of the "inbox" queue that will be bound to all subscription keys (called queues
|
62
|
+
# or destinations here). In other words, you only have one queue where all messages end up using this
|
63
|
+
# adapter, and it is bound to the relevant exchanges using routing keys and exchange information
|
64
|
+
# you provide in your messages.rb and subscribes_to calls. For example,
|
65
|
+
#
|
66
|
+
# in messages.rb:
|
67
|
+
# s.queue :hello_world, 'hello.world', :exchange_type => :direct, :exchange_name => 'amq.direct'
|
68
|
+
#
|
69
|
+
# in a processor:
|
70
|
+
# subscribes_to :hello_world, :routing_key => 'hello.#'
|
71
|
+
#
|
72
|
+
# in a model:
|
73
|
+
# publish :hello_world, 'Hello world!', :routing_key => 'hello.world'
|
74
|
+
|
75
|
+
|
76
|
+
# Note: in the event that you don't specify a routing_key on publish, the queue_name of the specified
|
77
|
+
# destination (as listed in messages.rb) will be used as the routing_key when publishing.
|
78
|
+
|
30
79
|
################################
|
31
80
|
# Beanstalk Adapter Properties #
|
32
81
|
################################
|
data/init.rb
CHANGED
data/lib/activemessaging.rb
CHANGED
@@ -1,7 +1,13 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
if defined?(Rails::Railtie)
|
5
|
+
require 'activemessaging/railtie.rb'
|
6
|
+
end
|
7
|
+
|
1
8
|
module ActiveMessaging
|
2
|
-
|
3
|
-
|
4
|
-
ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
9
|
+
|
10
|
+
ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
5
11
|
|
6
12
|
# Used to indicate that the processing for a thread shoud complete
|
7
13
|
class StopProcessingException < Interrupt #:nodoc:
|
@@ -17,18 +23,27 @@ module ActiveMessaging
|
|
17
23
|
class StopFilterException < Exception #:nodoc:
|
18
24
|
end
|
19
25
|
|
20
|
-
def
|
26
|
+
def self.logger
|
21
27
|
@@logger = nil unless defined? @@logger
|
22
|
-
@@logger ||=
|
23
|
-
@@logger ||= ActiveRecord::Base.logger if defined? ActiveRecord
|
28
|
+
@@logger ||= Rails.logger if defined? Rails
|
24
29
|
@@logger ||= Logger.new(STDOUT)
|
25
30
|
@@logger
|
26
31
|
end
|
27
32
|
|
28
|
-
|
33
|
+
def self.logger=(logger)
|
34
|
+
@@logger = logger
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.app_root
|
38
|
+
@@app_root ||= (ENV['APP_ROOT'] || (defined?(::Rails) && ::Rails.root) || ENV['RAILS_ROOT'] || File.dirname($0))
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.app_env
|
42
|
+
@@app_env ||= (ENV['APP_ENV'] || (defined?(::Rails) && ::Rails.env) || ENV['RAILS_ENV'] || 'development')
|
43
|
+
end
|
44
|
+
|
29
45
|
def self.load_extensions
|
30
46
|
require 'logger'
|
31
|
-
require 'activemessaging/support'
|
32
47
|
require 'activemessaging/gateway'
|
33
48
|
require 'activemessaging/adapter'
|
34
49
|
require 'activemessaging/message_sender'
|
@@ -42,32 +57,28 @@ module ActiveMessaging
|
|
42
57
|
adapter_name = File.basename(a, ".rb")
|
43
58
|
require 'activemessaging/adapters/' + adapter_name
|
44
59
|
rescue RuntimeError, LoadError => e
|
45
|
-
logger.
|
60
|
+
logger.warn "ActiveMessaging: adapter #{adapter_name} not loaded: #{ e.message }"
|
46
61
|
end
|
47
62
|
end
|
48
63
|
end
|
49
64
|
|
50
65
|
def self.load_config
|
51
|
-
path = File.expand_path("#{
|
66
|
+
path = File.expand_path("#{app_root}/config/messaging.rb")
|
52
67
|
begin
|
53
68
|
load path
|
54
69
|
rescue MissingSourceFile
|
55
|
-
logger.
|
70
|
+
logger.error "ActiveMessaging: no '#{path}' file to load"
|
56
71
|
rescue
|
57
72
|
raise $!, " ActiveMessaging: problems trying to load '#{path}': \n\t#{$!.message}"
|
58
73
|
end
|
59
74
|
end
|
60
75
|
|
61
76
|
def self.load_processors(first=true)
|
62
|
-
|
63
|
-
load
|
64
|
-
|
65
|
-
load APP_ROOT + '/vendor/plugins/activemessaging/lib/activemessaging/filter.rb' unless defined?(ActiveMessaging::Filter)
|
66
|
-
logger.debug "ActiveMessaging: Loading #{APP_ROOT + '/app/processors/application.rb'}" if first
|
67
|
-
load APP_ROOT + '/app/processors/application.rb' if File.exist?("#{APP_ROOT}/app/processors/application.rb")
|
68
|
-
Dir[APP_ROOT + '/app/processors/*.rb'].each do |f|
|
77
|
+
logger.info "ActiveMessaging: Loading #{app_root}/app/processors/application.rb" if first
|
78
|
+
load "#{app_root}/app/processors/application.rb" if File.exist?("#{app_root}/app/processors/application.rb")
|
79
|
+
Dir["#{app_root}/app/processors/*.rb"].each do |f|
|
69
80
|
unless f.match(/\/application.rb/)
|
70
|
-
logger.
|
81
|
+
logger.info "ActiveMessaging: Loading #{f}" if first
|
71
82
|
load f
|
72
83
|
end
|
73
84
|
end
|
@@ -92,17 +103,20 @@ module ActiveMessaging
|
|
92
103
|
|
93
104
|
def self.start
|
94
105
|
if ActiveMessaging::Gateway.subscriptions.empty?
|
95
|
-
err_msg =
|
106
|
+
err_msg = <<-EOM
|
96
107
|
|
97
|
-
ActiveMessaging Error: No subscriptions.
|
98
|
-
|
99
|
-
|
108
|
+
ActiveMessaging Error: No subscriptions.
|
109
|
+
|
110
|
+
If you have no processor classes in app/processors, add them using the command:
|
111
|
+
script/generate processor DoSomething"
|
100
112
|
|
101
|
-
If you have processor classes, make sure they include in the class a call to 'subscribes_to':
|
102
|
-
|
103
|
-
|
113
|
+
If you have processor classes, make sure they include in the class a call to 'subscribes_to':
|
114
|
+
class DoSomethingProcessor < ActiveMessaging::Processor
|
115
|
+
subscribes_to :do_something
|
116
|
+
# ...
|
117
|
+
end
|
104
118
|
|
105
|
-
EOM
|
119
|
+
EOM
|
106
120
|
puts err_msg
|
107
121
|
logger.error err_msg
|
108
122
|
exit
|
@@ -112,19 +126,3 @@ EOM
|
|
112
126
|
end
|
113
127
|
|
114
128
|
end
|
115
|
-
|
116
|
-
#load these once to start with
|
117
|
-
ActiveMessaging.load_activemessaging
|
118
|
-
|
119
|
-
# reload these on each Rails request - leveraging Dispatcher semantics for consistency
|
120
|
-
if defined? Rails
|
121
|
-
ActiveMessaging.logger.info "Rails available: Adding dispatcher prepare callback."
|
122
|
-
require 'dispatcher' unless defined?(::Dispatcher)
|
123
|
-
|
124
|
-
# add processors and config to on_prepare if supported (rails 1.2+)
|
125
|
-
if ::Dispatcher.respond_to? :to_prepare
|
126
|
-
::Dispatcher.to_prepare :activemessaging do
|
127
|
-
ActiveMessaging.reload_activemessaging
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
require 'carrot'
|
2
|
+
require 'digest/md5'
|
3
|
+
require 'bert'
|
4
|
+
|
5
|
+
# make sure ActiveMessaging::Processor is already loaded so we actually override it!
|
6
|
+
require 'activemessaging/processor'
|
7
|
+
require 'activemessaging/adapters/base'
|
8
|
+
|
9
|
+
require 'emissary/message'
|
10
|
+
|
11
|
+
module ActiveMessaging
|
12
|
+
class Processor
|
13
|
+
def self.subscribes_to destination_name, headers={}
|
14
|
+
# let's default to using the same exchange_type/exchange_name as defined in the messages.rb
|
15
|
+
# for the given destination. XXX: THIS IS A BIG TIME MONKEY PATCH! Might consider pushing a
|
16
|
+
# proper patch upstream instead of jury-rigging this.
|
17
|
+
d = ActiveMessaging::Gateway.find_destination(destination_name)
|
18
|
+
type, name = [ d.publish_headers[:exchange_type], d.publish_headers[:exchange_name] ]
|
19
|
+
ActiveMessaging::Gateway.subscribe_to destination_name, self, { :exchange_type => type, :exchange_name => name }.merge(headers)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module Adapters
|
24
|
+
module Amqp
|
25
|
+
class Connection
|
26
|
+
include ActiveMessaging::Adapter
|
27
|
+
register :amqp
|
28
|
+
|
29
|
+
SERVER_RETRY_MAX_ATTEMPTS = 10
|
30
|
+
|
31
|
+
DEFAULT_QUEUE_CONFIG = {
|
32
|
+
:durable => true,
|
33
|
+
:auto_delete => false,
|
34
|
+
:exclusive => true
|
35
|
+
}
|
36
|
+
|
37
|
+
class InvalidExchangeType < ArgumentError; end
|
38
|
+
|
39
|
+
def initialize config = {}
|
40
|
+
@connect_options = {
|
41
|
+
:user => config[:user] || 'guest',
|
42
|
+
:pass => config[:pass] || 'guest',
|
43
|
+
:host => config[:host] || 'localhost',
|
44
|
+
:port => config[:port] || (config[:ssl] ? 5671 : 5672),
|
45
|
+
:vhost => config[:vhost] || nil,
|
46
|
+
:ssl => config[:ssl] || false,
|
47
|
+
:ssl_verify => config[:ssl_verify] || OpenSSL::SSL::VERIFY_PEER,
|
48
|
+
}
|
49
|
+
|
50
|
+
@debug = config[:debug].to_i rescue 0
|
51
|
+
|
52
|
+
Carrot.logging = true unless @debug < 5
|
53
|
+
|
54
|
+
@auto_generated_queue = false
|
55
|
+
unless config[:queue_name]
|
56
|
+
@queue_name = Digest::MD5.hexdigest Time.now.to_s
|
57
|
+
@auto_generated_queue = true
|
58
|
+
else
|
59
|
+
@queue_name = config[:queue_name]
|
60
|
+
end
|
61
|
+
|
62
|
+
@queue_config = DEFAULT_QUEUE_CONFIG
|
63
|
+
unless @auto_generated_queue
|
64
|
+
@queue_config.merge({
|
65
|
+
:durable => !!config[:queue_durable],
|
66
|
+
:auto_delete => !!config[:queue_auto_delete],
|
67
|
+
:exclusive => !!config[:queue_exclusive]
|
68
|
+
})
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def received message, headers = {}
|
73
|
+
puts "Received Message - ACK'ing with delivery_tag '#{message.headers[:delivery_tag]}'" if @debug > 0
|
74
|
+
client.server.send_frame(::Carrot::AMQP::Protocol::Basic::Ack.new(:delivery_tag => message.headers[:delivery_tag]))
|
75
|
+
end
|
76
|
+
|
77
|
+
def unreceive message, headers = {}
|
78
|
+
puts "Un-Receiving Message - REJECTing with delivery_tag '#{message.headers[:delivery_tag]}'" if @debug > 0
|
79
|
+
client.server.send_frame(::Carrot::AMQP::Protocol::Basic::Reject.new(:delivery_tag => message.headers[:delivery_tag]))
|
80
|
+
end
|
81
|
+
|
82
|
+
def receive
|
83
|
+
while true
|
84
|
+
message = queue.pop(:ack => true)
|
85
|
+
unless message.nil?
|
86
|
+
message = AmqpMessage.decode(message).stamp_received! unless message.nil?
|
87
|
+
message.delivery_tag = queue.delivery_tag
|
88
|
+
puts "RECEIVE: #{message.inspect}" if @debug
|
89
|
+
return message
|
90
|
+
end
|
91
|
+
sleep 0.2
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def send queue_name, data, headers = {}
|
96
|
+
headers[:routing_key] ||= queue_name
|
97
|
+
message = AmqpMessage.new({:headers => headers, :data => data}, queue_name)
|
98
|
+
|
99
|
+
if @debug > 0
|
100
|
+
puts "Sending the following message: "; pp message
|
101
|
+
end
|
102
|
+
|
103
|
+
begin
|
104
|
+
exchange(*exchange_info(headers)).publish(message.stamp_sent!.encode, :key => headers[:routing_key])
|
105
|
+
rescue ::Carrot::AMQP::Server::ServerDown
|
106
|
+
retry_attempts = retry_attempts.nil? ? 1 : retry_attempts + 1
|
107
|
+
sleep(retry_attempts * 0.25)
|
108
|
+
retry unless retry_attempts >= SERVER_RETRY_MAX_ATTEMPTS
|
109
|
+
raise e
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def subscribe queue_name, headers = {}, subId = nil
|
114
|
+
if @debug > 1
|
115
|
+
puts "Begin Subscribe Request:"
|
116
|
+
puts " Queue Name: #{queue_name.inspect}"
|
117
|
+
puts " Headers: #{headers.inspect}"
|
118
|
+
puts " subId: #{subId.inspect}"
|
119
|
+
puts " EXCH INFO: #{exchange_info(headers).inspect}"
|
120
|
+
puts "End Subscribe Request."
|
121
|
+
end
|
122
|
+
|
123
|
+
routing_key = headers[:routing_key] || queue_name
|
124
|
+
queue.bind(exchange(*exchange_info(headers)), :key => routing_key)
|
125
|
+
end
|
126
|
+
|
127
|
+
def unsubscribe(queue_name, headers={}, subId=nil)
|
128
|
+
if @debug > 1
|
129
|
+
puts "Begin UNsubscribe Request:"
|
130
|
+
puts " Queue Name: #{queue_name.inspect}"
|
131
|
+
puts " Headers: #{headers.inspect}"
|
132
|
+
puts " subId: #{subId.inspect}"
|
133
|
+
puts "End UNsubscribe Request."
|
134
|
+
end
|
135
|
+
|
136
|
+
routing_key = headers[:routing_key] || queue_name
|
137
|
+
queue.unbind(exchange(*exchange_info(headers)), :key => routing_key)
|
138
|
+
end
|
139
|
+
|
140
|
+
def disconnect(headers={})
|
141
|
+
@client.stop
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def exchange_info headers
|
147
|
+
[ (headers[:exchange_type].to_sym rescue nil) || :direct, headers[:exchange_name] || nil]
|
148
|
+
end
|
149
|
+
|
150
|
+
def exchange type, name, *args
|
151
|
+
type = type.to_sym rescue nil
|
152
|
+
unless [:topic, :fanout, :direct].include? type
|
153
|
+
raise InvalidExchangeType, "The carrot library does not support an exchange type of '#{type.inspect}'"
|
154
|
+
end
|
155
|
+
|
156
|
+
name ||= "amq.#{type}"
|
157
|
+
puts "Exchange [#{type}::#{name}]: #{args.inspect}" if @debug > 3
|
158
|
+
(@exchanges||={})[name] ||= ::Carrot::AMQP::Exchange.new client, type, name, *args
|
159
|
+
end
|
160
|
+
|
161
|
+
def queue
|
162
|
+
return @queue unless @queue.nil?
|
163
|
+
puts "Queue [#{@queue_name}]: #{@queue_config.inspect}" if @debug > 0
|
164
|
+
@queue ||= client.queue(@queue_name, @queue_config)
|
165
|
+
end
|
166
|
+
|
167
|
+
def client
|
168
|
+
return @client unless @client.nil?
|
169
|
+
puts "Client [amqp]: #{@connect_options.inspect}" if @debug > 0
|
170
|
+
@client ||= Carrot.new(@connect_options)
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
class AmqpMessage < Emissary::Message
|
176
|
+
attr_reader :command
|
177
|
+
attr_accessor :destination, :delivery_tag
|
178
|
+
|
179
|
+
def initialize(data, queue_name = nil)
|
180
|
+
data[:data] = data.delete(:body) unless (data[:data] && !data[:body])
|
181
|
+
|
182
|
+
super(data)
|
183
|
+
|
184
|
+
@delivery_tag ||= (data[:headers][:delivery_tag] rescue nil)
|
185
|
+
@destination ||= (data[:headers][:destination] rescue nil) || queue_name || routing_key
|
186
|
+
|
187
|
+
@command = "MESSAGE"
|
188
|
+
end
|
189
|
+
|
190
|
+
alias :body :data
|
191
|
+
|
192
|
+
def headers
|
193
|
+
super.merge({
|
194
|
+
:destination => routing_key,
|
195
|
+
:delivery_tag => @delivery_tag
|
196
|
+
})
|
197
|
+
end
|
198
|
+
|
199
|
+
def matches_subscription?(subscription)
|
200
|
+
# use routing key first, otherwise, use the defined destination value
|
201
|
+
destination = subscription.subscribe_headers[:routing_key] || subscription.destination.value.to_s
|
202
|
+
|
203
|
+
if destination.match(/(\#|\*)/)
|
204
|
+
dest_regex = ::Regexp.new(destination.gsub('.*', '[.][^.]+').gsub(/\.\#.*/, '[.].*'))
|
205
|
+
!!(headers[:destination].to_s =~ dest_regex)
|
206
|
+
else
|
207
|
+
!!(headers[:destination].to_s == destination)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
@@ -6,6 +6,7 @@ require 'base64'
|
|
6
6
|
require 'cgi'
|
7
7
|
require 'time'
|
8
8
|
require 'uri'
|
9
|
+
require 'rexml/document'
|
9
10
|
|
10
11
|
require 'activemessaging/adapters/base'
|
11
12
|
|
@@ -204,8 +205,7 @@ module ActiveMessaging
|
|
204
205
|
|
205
206
|
# Sign the string
|
206
207
|
sorted_params = params.sort_by { |key,value| key.downcase }
|
207
|
-
|
208
|
-
string_to_sign = joined_params.to_s
|
208
|
+
string_to_sign = sorted_params.collect { |key, value| key.to_s + value.to_s }.join()
|
209
209
|
digest = OpenSSL::Digest::Digest.new('sha1')
|
210
210
|
hmac = OpenSSL::HMAC.digest(digest, @secret_access_key, string_to_sign)
|
211
211
|
params['Signature'] = Base64.encode64(hmac).chomp
|
@@ -417,4 +417,4 @@ module ActiveMessaging
|
|
417
417
|
|
418
418
|
end
|
419
419
|
end
|
420
|
-
end
|
420
|
+
end
|
@@ -9,11 +9,12 @@ module ActiveMessaging
|
|
9
9
|
class Connection < ActiveMessaging::Adapters::BaseConnection
|
10
10
|
register :stomp
|
11
11
|
|
12
|
-
attr_accessor :stomp_connection, :retryMax, :deadLetterQueue, :configuration
|
12
|
+
attr_accessor :stomp_connection, :retryMax, :deadLetterQueue, :configuration, :deadLetterQueuePrefix
|
13
13
|
|
14
14
|
def initialize(cfg)
|
15
15
|
@retryMax = cfg[:retryMax] || 0
|
16
16
|
@deadLetterQueue = cfg[:deadLetterQueue] || nil
|
17
|
+
@deadLetterQueuePrefix = cfg[:deadLetterQueuePrefix] || nil
|
17
18
|
|
18
19
|
cfg[:login] ||= ""
|
19
20
|
cfg[:passcode] ||= ""
|
@@ -31,7 +32,22 @@ module ActiveMessaging
|
|
31
32
|
connect_headers['client-id'] = cfg[:clientId] if cfg[:clientId]
|
32
33
|
@stomp_connection = ::Stomp::Connection.new(cfg[:login],cfg[:passcode],cfg[:host],cfg[:port].to_i,cfg[:reliable],cfg[:reconnectDelay], connect_headers)
|
33
34
|
end
|
34
|
-
|
35
|
+
|
36
|
+
# Checks if the connection supports dead letter queues
|
37
|
+
def supports_dlq?
|
38
|
+
!@deadLetterQueue.nil? || !@deadLetterQueuePrefix.nil?
|
39
|
+
end
|
40
|
+
|
41
|
+
# add the dead letter queue prefix to the destination
|
42
|
+
def add_dlq_prefix(destination)
|
43
|
+
if (ri = destination.rindex("/"))
|
44
|
+
destination.clone.insert(ri + 1, @deadLetterQueuePrefix)
|
45
|
+
else
|
46
|
+
@deadLetterQueuePrefix + destination
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
35
51
|
# called to cleanly get rid of connection
|
36
52
|
def disconnect
|
37
53
|
@stomp_connection.disconnect
|
@@ -80,10 +96,9 @@ module ActiveMessaging
|
|
80
96
|
end
|
81
97
|
end
|
82
98
|
|
83
|
-
def unreceive message, headers={}
|
99
|
+
def unreceive message, headers={}
|
84
100
|
retry_count = message.headers['a13g-retry-count'].to_i || 0
|
85
101
|
transaction_id = "transaction-#{message.headers['message-id']}-#{retry_count}"
|
86
|
-
|
87
102
|
# start a transaction, send the message back to the original destination
|
88
103
|
@stomp_connection.begin(transaction_id)
|
89
104
|
begin
|
@@ -91,11 +106,24 @@ module ActiveMessaging
|
|
91
106
|
if @retryMax > 0
|
92
107
|
retry_headers = message.headers.stringify_keys
|
93
108
|
retry_headers['transaction']= transaction_id
|
94
|
-
retry_headers.delete('content-
|
95
|
-
retry_headers.delete('content-
|
96
|
-
|
109
|
+
content_type_header = retry_headers.delete('content-type')
|
110
|
+
content_length_header = retry_headers.delete('content-length')
|
111
|
+
# If the content-length header in the original message is nil
|
112
|
+
# then we need to set the :suppress_content_length option so
|
113
|
+
# that the stomp client does not set the content-length of the
|
114
|
+
# retried message. This option will allow ActiveMQ to interpret the
|
115
|
+
# message as a TextMessage.
|
116
|
+
# This is somewhat of a hack because the setting of the :suppress_content_length
|
117
|
+
# header is usually done in the messaging.rb and is removed by the time
|
118
|
+
# the unreceive message is called. So I am making some assumptions here
|
119
|
+
# on whether or not to set the option
|
120
|
+
if content_type_header and content_type_header.include?('text/plain') && content_length_header.nil?
|
121
|
+
retry_headers[:suppress_content_length] = true
|
122
|
+
end
|
123
|
+
|
97
124
|
retry_destination = retry_headers.delete('destination')
|
98
|
-
|
125
|
+
retry_destination = headers[:destination] if headers[:destination]
|
126
|
+
|
99
127
|
if retry_count < @retryMax
|
100
128
|
# now send the message back to the destination
|
101
129
|
# set the headers for message id, priginal message id, and retry count
|
@@ -108,15 +136,23 @@ module ActiveMessaging
|
|
108
136
|
retry_headers['a13g-retry-count'] = retry_count + 1
|
109
137
|
|
110
138
|
# send the updated message to retry in the same transaction
|
139
|
+
logger.warn "retrying message on #{retry_destination}"
|
111
140
|
self.stomp_publish(retry_destination, message.body, retry_headers)
|
112
141
|
|
113
|
-
elsif retry_count >= @retryMax &&
|
142
|
+
elsif retry_count >= @retryMax && supports_dlq?
|
114
143
|
# send the 'poison pill' message to the dead letter queue - make it persistent by default
|
115
|
-
retry_headers['a13g-original-destination'] = retry_headers.delete('destination')
|
144
|
+
retry_headers['a13g-original-destination'] = retry_destination #retry_headers.delete('destination')
|
116
145
|
retry_headers['persistent'] = true
|
117
146
|
retry_headers.delete('message-id')
|
118
|
-
|
119
|
-
|
147
|
+
|
148
|
+
# If the prefix option is set then put the prefix after the /queue/ or /topic/
|
149
|
+
if (@deadLetterQueuePrefix)
|
150
|
+
dlq = add_dlq_prefix(retry_destination)
|
151
|
+
else
|
152
|
+
dlq = @deadLetterQueue
|
153
|
+
end
|
154
|
+
logger.warn "putting message on DLQ: #{dlq}"
|
155
|
+
self.stomp_publish(dlq, message.body, retry_headers)
|
120
156
|
end
|
121
157
|
|
122
158
|
end
|
@@ -164,4 +200,4 @@ module ActiveMessaging
|
|
164
200
|
|
165
201
|
end
|
166
202
|
end
|
167
|
-
end
|
203
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
#
|
2
|
+
# This is meant to avoid the need to use a broker in development, and generally make development mode easier
|
3
|
+
#
|
4
|
+
module ActiveMessaging
|
5
|
+
module Adapters
|
6
|
+
module Synch
|
7
|
+
|
8
|
+
class Connection < ActiveMessaging::Adapters::BaseConnection
|
9
|
+
register :synch
|
10
|
+
|
11
|
+
#configurable params
|
12
|
+
attr_accessor :configuration, :max_process, :processing_pids, :use_fork
|
13
|
+
|
14
|
+
#generic init method needed by a13g
|
15
|
+
def initialize cfg
|
16
|
+
ActiveMessaging.logger.debug "ActiveMessaging::Adapters::Synch::Connection.initialize: #{cfg.inspect}"
|
17
|
+
@configuration = cfg
|
18
|
+
|
19
|
+
@use_fork = !!@configuration[:use_fork]
|
20
|
+
|
21
|
+
# max at once
|
22
|
+
@max_process = 10
|
23
|
+
# keep track of the processes running
|
24
|
+
@processing_pids = {}
|
25
|
+
|
26
|
+
if use_fork
|
27
|
+
Thread.new {
|
28
|
+
watch_processes
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def watch_processes
|
34
|
+
while true
|
35
|
+
begin
|
36
|
+
pid = Process.wait(0, Process::WNOHANG)
|
37
|
+
if m = processing_pids.delete(pid)
|
38
|
+
ActiveMessaging.logger.debug "ActiveMessaging:synch - processing complete for pid (#{pid}):\n\t#{m}"
|
39
|
+
end
|
40
|
+
sleep(0.5)
|
41
|
+
rescue
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def send destination_name, message_body, message_headers={}
|
47
|
+
message = Message.new(message_body, 'id', message_headers, destination_name, 'MESSAGE')
|
48
|
+
|
49
|
+
if use_fork
|
50
|
+
|
51
|
+
if processing_pids.size > max_process
|
52
|
+
ActiveMessaging.logger.debug "ActiveMessaging:synch too many processes: #{processing_pids.size} > #{max_process}"
|
53
|
+
sleep(0.5)
|
54
|
+
end
|
55
|
+
|
56
|
+
pid = fork {
|
57
|
+
ActiveMessaging.logger.debug "\n-------------------- ActiveMessaging:synch start fork dispath (#{Process.pid}) --------------------"
|
58
|
+
ActiveMessaging::Gateway.prepare_application
|
59
|
+
ActiveMessaging::Gateway._dispatch(message)
|
60
|
+
ActiveMessaging::Gateway.reset_application
|
61
|
+
ActiveMessaging.logger.debug "-------------------- ActiveMessaging:synch end fork dispath (#{Process.pid})--------------------\n"
|
62
|
+
}
|
63
|
+
|
64
|
+
Process.detach(pid)
|
65
|
+
processing_pids[pid] = "Destination: #{destination_name}, Message: #{message_body}"
|
66
|
+
|
67
|
+
else
|
68
|
+
|
69
|
+
ActiveMessaging.logger.debug "\n-------------------- ActiveMessaging:synch before dispath --------------------"
|
70
|
+
ActiveMessaging::Gateway.prepare_application
|
71
|
+
ActiveMessaging::Gateway._dispatch(message)
|
72
|
+
ActiveMessaging::Gateway.reset_application
|
73
|
+
ActiveMessaging.logger.debug "-------------------- ActiveMessaging:synch after dispath --------------------\n"
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
class Message < ActiveMessaging::BaseMessage
|
82
|
+
attr_accessor :command
|
83
|
+
|
84
|
+
def initialize body, id, headers, destination, command='MESSAGE'
|
85
|
+
# ActiveMessaging.logger.debug "Message headers:#{headers.inspect}, id:#{id}, body:#{body}, destination:#{destination}, command:#{command}"
|
86
|
+
@headers, @body, @destination, @command = headers, body, destination, command
|
87
|
+
headers['destination'] = destination
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -111,7 +111,9 @@ module ActiveMessaging
|
|
111
111
|
def connection broker_name='default'
|
112
112
|
return @@connections[broker_name] if @@connections.has_key?(broker_name)
|
113
113
|
config = load_connection_configuration(broker_name)
|
114
|
-
|
114
|
+
adapter_class = Gateway.adapters[config[:adapter]]
|
115
|
+
raise "Unknown messaging adapter #{config[:adapter].inspect}!" if adapter_class.nil?
|
116
|
+
@@connections[broker_name] = adapter_class.new(config)
|
115
117
|
end
|
116
118
|
|
117
119
|
def register_adapter adapter_name, adapter_class
|
@@ -188,16 +190,12 @@ module ActiveMessaging
|
|
188
190
|
end
|
189
191
|
|
190
192
|
def prepare_application
|
191
|
-
if defined?
|
192
|
-
# Dispatcher.prepare_application_for_dispatch
|
193
|
+
if defined? ActiveRecord
|
193
194
|
ActiveRecord::Base.verify_active_connections!
|
194
195
|
end
|
195
196
|
end
|
196
197
|
|
197
198
|
def reset_application
|
198
|
-
if defined? Rails
|
199
|
-
# Dispatcher.reset_application_after_dispatch
|
200
|
-
end
|
201
199
|
end
|
202
200
|
|
203
201
|
def dispatch(message)
|
@@ -210,6 +208,7 @@ module ActiveMessaging
|
|
210
208
|
ActiveMessaging.logger.error exc.backtrace.join("\n\t")
|
211
209
|
raise exc
|
212
210
|
ensure
|
211
|
+
ActiveMessaging.logger.flush rescue nil
|
213
212
|
reset_application
|
214
213
|
end
|
215
214
|
}
|
@@ -223,9 +222,9 @@ module ActiveMessaging
|
|
223
222
|
if message.matches_subscription?(subscription) then
|
224
223
|
processed = true
|
225
224
|
routing = {
|
226
|
-
:receiver=>subscription.processor_class,
|
227
|
-
:destination=>subscription.destination,
|
228
|
-
:direction
|
225
|
+
:receiver => subscription.processor_class,
|
226
|
+
:destination => subscription.destination,
|
227
|
+
:direction => :incoming
|
229
228
|
}
|
230
229
|
begin
|
231
230
|
execute_filter_chain(:incoming, message, routing) do |m|
|
@@ -358,11 +357,11 @@ module ActiveMessaging
|
|
358
357
|
end
|
359
358
|
|
360
359
|
def load_connection_configuration(label='default')
|
361
|
-
@broker_yml = YAML::load(ERB.new(IO.read(File.join(
|
360
|
+
@broker_yml = YAML::load(ERB.new(IO.read(File.join(ActiveMessaging.app_root, 'config', 'broker.yml'))).result) if @broker_yml.nil?
|
362
361
|
if label == 'default'
|
363
|
-
config = @broker_yml[
|
362
|
+
config = @broker_yml[ActiveMessaging.app_env].symbolize_keys
|
364
363
|
else
|
365
|
-
config = @broker_yml[
|
364
|
+
config = @broker_yml[ActiveMessaging.app_env][label].symbolize_keys
|
366
365
|
end
|
367
366
|
config[:adapter] = config[:adapter].to_sym if config[:adapter]
|
368
367
|
config[:adapter] ||= :stomp
|
@@ -13,8 +13,7 @@ module ActiveMessaging
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def logger()
|
16
|
-
@@logger
|
17
|
-
@@logger
|
16
|
+
@@logger ||= ActiveMessaging.logger
|
18
17
|
end
|
19
18
|
|
20
19
|
def on_message(message)
|
@@ -37,7 +36,7 @@ module ActiveMessaging
|
|
37
36
|
logger.error "Processor:process! - AbortMessageException caught."
|
38
37
|
raise rpe
|
39
38
|
rescue Object=>ex
|
40
|
-
logger.error "Processor:process! - error in on_error, will propagate no further: #{ex.message}"
|
39
|
+
logger.error "Processor:process! - error in on_error, will propagate no further: #{ex.message}\n\t#{ex.backtrace.join("\n\t")}"
|
41
40
|
end
|
42
41
|
end
|
43
42
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'rails'
|
3
|
+
require 'activemessaging'
|
4
|
+
|
5
|
+
module ActiveMessaging
|
6
|
+
class Railtie < Rails::Railtie
|
7
|
+
|
8
|
+
initializer 'activemessaging.initialize' do
|
9
|
+
|
10
|
+
ActiveMessaging.load_activemessaging
|
11
|
+
|
12
|
+
if defined? Rails
|
13
|
+
ActiveMessaging.logger.info "ActiveMessaging: Rails available: Adding dispatcher prepare callback."
|
14
|
+
ActionDispatch::Callbacks.to_prepare :activemessaging do
|
15
|
+
ActiveMessaging.reload_activemessaging
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -1,34 +1,34 @@
|
|
1
|
-
class TraceFilter< ActiveMessaging::Filter
|
2
|
-
include ActiveMessaging::MessageSender
|
3
|
-
|
4
|
-
def initialize(options)
|
5
|
-
@queue = options[:queue]
|
6
|
-
TraceFilter.publishes_to @queue
|
7
|
-
end
|
8
|
-
|
9
|
-
def process message, routing
|
10
|
-
|
11
|
-
unless ( routing[:destination].name == @queue ) then
|
12
|
-
ActiveMessaging.logger.debug "Trace: direction = #{routing[:direction]} publisher=#{routing[:publisher]} queue=#{routing[:destination].name} @queue=#{@queue}"
|
13
|
-
if routing[:direction].to_sym==:outgoing then
|
14
|
-
"trace from outgoing"
|
15
|
-
publish @queue, "<sent>"+
|
16
|
-
"<from>#{routing[:publisher]}</from>" +
|
17
|
-
"<queue>#{routing[:destination].name}</queue>" +
|
18
|
-
"<message>#{message.body}</message>" +
|
19
|
-
"</sent>"
|
20
|
-
end
|
21
|
-
if routing[:direction].to_sym==:incoming then
|
22
|
-
"trace from incoming"
|
23
|
-
publish @queue, "<received>"+
|
24
|
-
"<by>#{routing[:receiver]}</by>" +
|
25
|
-
"<queue>#{routing[:destination].name}</queue>" +
|
26
|
-
"<message>#{message.body}</message>" +
|
27
|
-
"</received>"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
|
1
|
+
class TraceFilter< ActiveMessaging::Filter
|
2
|
+
include ActiveMessaging::MessageSender
|
3
|
+
|
4
|
+
def initialize(options)
|
5
|
+
@queue = options[:queue]
|
6
|
+
TraceFilter.publishes_to @queue
|
7
|
+
end
|
8
|
+
|
9
|
+
def process message, routing
|
10
|
+
|
11
|
+
unless ( routing[:destination].name == @queue ) then
|
12
|
+
ActiveMessaging.logger.debug "Trace: direction = #{routing[:direction]} publisher=#{routing[:publisher]} queue=#{routing[:destination].name} @queue=#{@queue}"
|
13
|
+
if routing[:direction].to_sym==:outgoing then
|
14
|
+
"trace from outgoing"
|
15
|
+
publish @queue, "<sent>"+
|
16
|
+
"<from>#{routing[:publisher]}</from>" +
|
17
|
+
"<queue>#{routing[:destination].name}</queue>" +
|
18
|
+
"<message>#{message.body}</message>" +
|
19
|
+
"</sent>"
|
20
|
+
end
|
21
|
+
if routing[:direction].to_sym==:incoming then
|
22
|
+
"trace from incoming"
|
23
|
+
publish @queue, "<received>"+
|
24
|
+
"<by>#{routing[:receiver]}</by>" +
|
25
|
+
"<queue>#{routing[:destination].name}</queue>" +
|
26
|
+
"<message>#{message.body}</message>" +
|
27
|
+
"</received>"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
File without changes
|
data/test/stomp_test.rb
CHANGED
@@ -69,11 +69,14 @@ class StompTest < Test::Unit::TestCase
|
|
69
69
|
:port=> "61613",
|
70
70
|
:reliable=>FALSE,
|
71
71
|
:reconnectDelay=> 5,
|
72
|
-
:clientId=> 'cid'
|
72
|
+
:clientId=> 'cid',
|
73
|
+
:deadLetterQueuePrefix=>"DLQ."}
|
73
74
|
|
74
75
|
@connection = ActiveMessaging::Adapters::Stomp::Connection.new(i)
|
75
76
|
assert_equal 4, @connection.retryMax
|
76
77
|
assert_equal '/queue/dlq', @connection.deadLetterQueue
|
78
|
+
assert_equal "DLQ.", @connection.deadLetterQueuePrefix
|
79
|
+
assert_equal true, @connection.supports_dlq?
|
77
80
|
end
|
78
81
|
|
79
82
|
def test_disconnect
|
@@ -123,9 +126,30 @@ class StompTest < Test::Unit::TestCase
|
|
123
126
|
@connection = ActiveMessaging::Adapters::Stomp::Connection.new({:retryMax=>4, :deadLetterQueue=>'/queue/dlq'})
|
124
127
|
@connection.stomp_connection.receive = @message
|
125
128
|
m = @connection.receive
|
129
|
+
m.headers["a13g-retry-count"] = 5
|
126
130
|
@connection.unreceive m, {:ack=>'client'}
|
127
131
|
end
|
128
132
|
|
133
|
+
def test_unreceive_with_dlq_prefix
|
134
|
+
@connection = ActiveMessaging::Adapters::Stomp::Connection.new({:retryMax=>4, :deadLetterQueuePrefix=>'DLQ.'})
|
135
|
+
@connection.stomp_connection.receive = @message
|
136
|
+
m = @connection.receive
|
137
|
+
m.headers["a13g-retry-count"] = 5
|
138
|
+
@connection.unreceive m, {:ack=>'client', :destination=>"/queue/myqueue"}
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_add_dlq_prefix
|
142
|
+
@connection = ActiveMessaging::Adapters::Stomp::Connection.new({:deadLetterQueuePrefix=>'DLQ.'})
|
143
|
+
dlq = @connection.add_dlq_prefix("/queue/myqueue")
|
144
|
+
assert_equal "/queue/DLQ.myqueue", dlq
|
145
|
+
dlq = @connection.add_dlq_prefix("/queue/something/myqueue")
|
146
|
+
assert_equal "/queue/something/DLQ.myqueue", dlq
|
147
|
+
dlq = @connection.add_dlq_prefix("/topic/myqueue")
|
148
|
+
assert_equal "/topic/DLQ.myqueue", dlq
|
149
|
+
dlq = @connection.add_dlq_prefix("myqueue")
|
150
|
+
assert_equal "DLQ.myqueue", dlq
|
151
|
+
end
|
152
|
+
|
129
153
|
end
|
130
154
|
|
131
155
|
end # if loaded
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activemessaging
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 61
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 8
|
9
|
+
- 1
|
10
|
+
version: 0.8.1
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Jon Tirsen
|
@@ -14,20 +20,26 @@ autorequire:
|
|
14
20
|
bindir: bin
|
15
21
|
cert_chain: []
|
16
22
|
|
17
|
-
date:
|
23
|
+
date: 2011-08-15 00:00:00 -04:00
|
18
24
|
default_executable:
|
19
25
|
dependencies:
|
20
26
|
- !ruby/object:Gem::Dependency
|
21
27
|
name: activesupport
|
22
|
-
|
23
|
-
|
24
|
-
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
25
31
|
requirements:
|
26
32
|
- - ">="
|
27
33
|
- !ruby/object:Gem::Version
|
34
|
+
hash: 23
|
35
|
+
segments:
|
36
|
+
- 1
|
37
|
+
- 0
|
38
|
+
- 0
|
28
39
|
version: 1.0.0
|
29
|
-
|
30
|
-
|
40
|
+
type: :runtime
|
41
|
+
version_requirements: *id001
|
42
|
+
description: ActiveMessaging is an attempt to bring the simplicity and elegance of rails development to the world of messaging. Messaging, (or event-driven architecture) is widely used for enterprise integration, with frameworks such as Java's JMS, and products such as ActiveMQ, Tibco, IBM MQSeries, etc. Now supporting Rails 3 as of version 0.8.0.
|
31
43
|
email: activemessaging-discuss@googlegroups.com
|
32
44
|
executables: []
|
33
45
|
|
@@ -68,12 +80,14 @@ files:
|
|
68
80
|
- init.rb
|
69
81
|
- lib/activemessaging.rb
|
70
82
|
- lib/activemessaging/adapter.rb
|
83
|
+
- lib/activemessaging/adapters/amqp.rb
|
71
84
|
- lib/activemessaging/adapters/asqs.rb
|
72
85
|
- lib/activemessaging/adapters/base.rb
|
73
86
|
- lib/activemessaging/adapters/beanstalk.rb
|
74
87
|
- lib/activemessaging/adapters/jms.rb
|
75
88
|
- lib/activemessaging/adapters/reliable_msg.rb
|
76
89
|
- lib/activemessaging/adapters/stomp.rb
|
90
|
+
- lib/activemessaging/adapters/synch.rb
|
77
91
|
- lib/activemessaging/adapters/test.rb
|
78
92
|
- lib/activemessaging/adapters/wmq.rb
|
79
93
|
- lib/activemessaging/base_message.rb
|
@@ -82,11 +96,11 @@ files:
|
|
82
96
|
- lib/activemessaging/message_sender.rb
|
83
97
|
- lib/activemessaging/named_base.rb
|
84
98
|
- lib/activemessaging/processor.rb
|
85
|
-
- lib/activemessaging/
|
99
|
+
- lib/activemessaging/railtie.rb
|
86
100
|
- lib/activemessaging/test_helper.rb
|
87
101
|
- lib/activemessaging/trace_filter.rb
|
102
|
+
- lib/tasks/start_consumers.rake
|
88
103
|
- poller.rb
|
89
|
-
- tasks/start_consumers.rake
|
90
104
|
- test/all_tests.rb
|
91
105
|
- test/app/config/broker.yml
|
92
106
|
- test/asqs_test.rb
|
@@ -103,26 +117,32 @@ homepage: http://github.com/kookster/activemessaging
|
|
103
117
|
licenses: []
|
104
118
|
|
105
119
|
post_install_message:
|
106
|
-
rdoc_options:
|
107
|
-
|
120
|
+
rdoc_options: []
|
121
|
+
|
108
122
|
require_paths:
|
109
123
|
- lib
|
110
124
|
required_ruby_version: !ruby/object:Gem::Requirement
|
125
|
+
none: false
|
111
126
|
requirements:
|
112
127
|
- - ">="
|
113
128
|
- !ruby/object:Gem::Version
|
129
|
+
hash: 3
|
130
|
+
segments:
|
131
|
+
- 0
|
114
132
|
version: "0"
|
115
|
-
version:
|
116
133
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
117
135
|
requirements:
|
118
136
|
- - ">="
|
119
137
|
- !ruby/object:Gem::Version
|
138
|
+
hash: 3
|
139
|
+
segments:
|
140
|
+
- 0
|
120
141
|
version: "0"
|
121
|
-
version:
|
122
142
|
requirements: []
|
123
143
|
|
124
144
|
rubyforge_project:
|
125
|
-
rubygems_version: 1.
|
145
|
+
rubygems_version: 1.4.2
|
126
146
|
signing_key:
|
127
147
|
specification_version: 3
|
128
148
|
summary: Official activemessaging gem, now hosted on github.com/kookster. (kookster prefix temporary)
|
@@ -1,17 +0,0 @@
|
|
1
|
-
if defined? Rails
|
2
|
-
ActiveMessaging.logger.debug "Rails available: Adding reload hooks."
|
3
|
-
require 'dispatcher' unless defined?(::Dispatcher)
|
4
|
-
::Dispatcher.class_eval do
|
5
|
-
|
6
|
-
def self.prepare_application_for_dispatch
|
7
|
-
disp = new(STDOUT)
|
8
|
-
disp.run_callbacks :before_dispatch
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.reset_application_after_dispatch
|
12
|
-
disp = new(STDOUT)
|
13
|
-
disp.run_callbacks :after_dispatch, :enumerator => :reverse_each
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
17
|
-
end
|