activemessaging 0.7.1 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|