rservicebus2 0.0.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.
- checksums.yaml +7 -0
- data/LICENSE +64 -0
- data/bin/return_messages_to_source_queue +114 -0
- data/bin/rsb_ctl +38 -0
- data/bin/rservicebus2 +14 -0
- data/bin/rservicebus2-create +107 -0
- data/bin/rservicebus2-init +104 -0
- data/bin/rservicebus2-transport +16 -0
- data/bin/send_empty_message +15 -0
- data/lib/rservicebus.rb +59 -0
- data/lib/rservicebus/agent.rb +54 -0
- data/lib/rservicebus/appresource.rb +65 -0
- data/lib/rservicebus/appresource/dir.rb +29 -0
- data/lib/rservicebus/appresource/file.rb +8 -0
- data/lib/rservicebus/appresource/fluiddb.rb +24 -0
- data/lib/rservicebus/appresource_configure.rb +33 -0
- data/lib/rservicebus/audit.rb +28 -0
- data/lib/rservicebus/circuitbreaker.rb +79 -0
- data/lib/rservicebus/config.rb +168 -0
- data/lib/rservicebus/cron_manager.rb +76 -0
- data/lib/rservicebus/endpointmapping.rb +72 -0
- data/lib/rservicebus/errormessage.rb +14 -0
- data/lib/rservicebus/handler_loader.rb +162 -0
- data/lib/rservicebus/handler_manager.rb +131 -0
- data/lib/rservicebus/helper_functions.rb +85 -0
- data/lib/rservicebus/host.rb +487 -0
- data/lib/rservicebus/message.rb +78 -0
- data/lib/rservicebus/message/statisticoutput.rb +7 -0
- data/lib/rservicebus/message/subscription.rb +10 -0
- data/lib/rservicebus/message/verboseoutput.rb +7 -0
- data/lib/rservicebus/monitor.rb +61 -0
- data/lib/rservicebus/monitor/csvdir.rb +52 -0
- data/lib/rservicebus/monitor/dir.rb +139 -0
- data/lib/rservicebus/monitor/dirnotifier.rb +101 -0
- data/lib/rservicebus/monitor/message.rb +11 -0
- data/lib/rservicebus/monitor/xmldir.rb +11 -0
- data/lib/rservicebus/monitor_configure.rb +71 -0
- data/lib/rservicebus/mq.rb +98 -0
- data/lib/rservicebus/mq/beanstalk.rb +72 -0
- data/lib/rservicebus/resource_manager.rb +69 -0
- data/lib/rservicebus/saga/base.rb +17 -0
- data/lib/rservicebus/saga/data.rb +20 -0
- data/lib/rservicebus/saga/manager.rb +128 -0
- data/lib/rservicebus/saga_loader.rb +118 -0
- data/lib/rservicebus/saga_storage.rb +18 -0
- data/lib/rservicebus/saga_storage/dir.rb +87 -0
- data/lib/rservicebus/saga_storage/inmemory.rb +37 -0
- data/lib/rservicebus/sendat_manager.rb +33 -0
- data/lib/rservicebus/sendat_storage.rb +20 -0
- data/lib/rservicebus/sendat_storage/file.rb +37 -0
- data/lib/rservicebus/sendat_storage/inmemory.rb +20 -0
- data/lib/rservicebus/state_manager.rb +30 -0
- data/lib/rservicebus/state_storage.rb +18 -0
- data/lib/rservicebus/state_storage/dir.rb +66 -0
- data/lib/rservicebus/state_storage/inmemory.rb +25 -0
- data/lib/rservicebus/statistic_manager.rb +86 -0
- data/lib/rservicebus/stats.rb +68 -0
- data/lib/rservicebus/subscription_manager.rb +31 -0
- data/lib/rservicebus/subscription_storage.rb +39 -0
- data/lib/rservicebus/subscription_storage/file.rb +42 -0
- data/lib/rservicebus/subscription_storage/redis.rb +69 -0
- data/lib/rservicebus/subscription_storage_configure.rb +19 -0
- data/lib/rservicebus/test.rb +2 -0
- data/lib/rservicebus/test/bus.rb +32 -0
- data/lib/rservicebus/transporter.rb +142 -0
- data/lib/rservicebus/usermessage/withpayload.rb +10 -0
- metadata +184 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'rservicebus/monitor'
|
2
|
+
require 'rservicebus/monitor/message'
|
3
|
+
|
4
|
+
module RServiceBus
|
5
|
+
# Configure Monitors for an rservicebus host
|
6
|
+
class ConfigureMonitor
|
7
|
+
# Constructor
|
8
|
+
# @param [RServiceBus::Host] host instance
|
9
|
+
# @param [Hash] resourceManager As hash[k,v] where k is the name of a
|
10
|
+
# resource, and v is the resource
|
11
|
+
def initialize(host, resource_manager)
|
12
|
+
@host = host
|
13
|
+
@resource_manager = resource_manager
|
14
|
+
|
15
|
+
@handler_list = {}
|
16
|
+
@resource_list = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
# Assigns appropriate resources to writable attributes in the handler that
|
20
|
+
# match keys in the resource hash
|
21
|
+
# @param [RServiceBus::Handler] handler
|
22
|
+
def set_app_resources(monitor)
|
23
|
+
RServiceBus.rlog "Checking app resources for: #{monitor.class.name}"
|
24
|
+
RServiceBus.rlog "If your attribute is not getting set, check that it is
|
25
|
+
in the 'attr_accessor' list"
|
26
|
+
@resource_manager.get_all.each do |k, v|
|
27
|
+
next unless monitor.class.method_defined?(k)
|
28
|
+
|
29
|
+
monitor.instance_variable_set("@#{k}", v.get_resource)
|
30
|
+
@resource_list[monitor.class.name] = [] if
|
31
|
+
@resource_list[monitor.class.name].nil?
|
32
|
+
@resource_list[monitor.class.name] << v
|
33
|
+
@host.log "App resource attribute, #{k}, set for: " +
|
34
|
+
monitor.class.name
|
35
|
+
end
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_monitors(env)
|
40
|
+
monitors = []
|
41
|
+
|
42
|
+
env.each do |k, v|
|
43
|
+
if v.is_a?(String) && k.start_with?('RSBOB_')
|
44
|
+
uri = URI.parse(v)
|
45
|
+
name = k.sub('RSBOB_', '')
|
46
|
+
monitor = nil
|
47
|
+
case uri.scheme
|
48
|
+
when 'csvdir'
|
49
|
+
require 'rservicebus/monitor/csvdir'
|
50
|
+
monitor = MonitorCsvDir.new(@host, name, uri)
|
51
|
+
when 'xmldir'
|
52
|
+
require 'rservicebus/monitor/xmldir'
|
53
|
+
monitor = MonitorXmlDir.new(@host, name, uri)
|
54
|
+
when 'dir'
|
55
|
+
require 'rservicebus/monitor/dir'
|
56
|
+
monitor = MonitorDir.new(@host, name, uri)
|
57
|
+
when 'dirnotifier'
|
58
|
+
require 'rservicebus/monitor/dirnotifier'
|
59
|
+
monitor = MonitorDirNotifier.new(@host, name, uri)
|
60
|
+
else
|
61
|
+
abort("Scheme, #{uri.scheme}, not recognised when configuring
|
62
|
+
Monitor, #{k}=#{v}")
|
63
|
+
end
|
64
|
+
set_app_resources(monitor)
|
65
|
+
monitors << monitor
|
66
|
+
end
|
67
|
+
end
|
68
|
+
monitors
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module RServiceBus
|
4
|
+
class JobTooBigError < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
# Wrapper base class for Queue implementations available to the applications,
|
8
|
+
# allowing rservicebus to instatiate and configure queue implementations at
|
9
|
+
# startup - dependency injection.
|
10
|
+
class MQ
|
11
|
+
attr_reader :local_queue_name
|
12
|
+
|
13
|
+
def self.get
|
14
|
+
mq_string = RServiceBus.get_value('RSBMQ', 'beanstalk://localhost')
|
15
|
+
uri = URI.parse(mq_string)
|
16
|
+
|
17
|
+
case uri.scheme
|
18
|
+
when 'beanstalk'
|
19
|
+
require 'rservicebus/MQ/Beanstalk'
|
20
|
+
mq = MQBeanstalk.new(uri)
|
21
|
+
else
|
22
|
+
abort("Scheme, #{uri.scheme}, not recognised when configuring mq,
|
23
|
+
#{string}")
|
24
|
+
end
|
25
|
+
|
26
|
+
mq
|
27
|
+
end
|
28
|
+
|
29
|
+
# Resources are attached, and are be specified using the URI syntax
|
30
|
+
# @param [URI] uri the type and location of queue,
|
31
|
+
# eg beanstalk://127.0.0.1/foo
|
32
|
+
# @param [Integer] timeout the amount of time to wait for a msg to arrive
|
33
|
+
def initialize(uri)
|
34
|
+
if uri.is_a? URI
|
35
|
+
@uri = uri
|
36
|
+
else
|
37
|
+
puts 'uri must be a valid URI'
|
38
|
+
abort
|
39
|
+
end
|
40
|
+
|
41
|
+
if uri.path == '' || uri.path == '/'
|
42
|
+
@local_queue_name = RServiceBus.get_value('APPNAME', 'RServiceBus')
|
43
|
+
else
|
44
|
+
@local_queue_name = uri.path
|
45
|
+
@local_queue_name[0] = ''
|
46
|
+
end
|
47
|
+
|
48
|
+
if @local_queue_name == ''
|
49
|
+
puts "@local_queue_name: #{@local_queue_name}"
|
50
|
+
puts 'Queue name must be supplied '
|
51
|
+
puts "*** uri, #{uri}, needs to contain a queue name"
|
52
|
+
puts '*** the structure is scheme://host[:port]/queuename'
|
53
|
+
abort
|
54
|
+
end
|
55
|
+
|
56
|
+
@timeout = RServiceBus.get_value('QUEUE_TIMEOUT', '5').to_i
|
57
|
+
connect(uri.host, uri.port)
|
58
|
+
subscribe(@local_queue_name)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Connect to the broker
|
62
|
+
# @param [String] host machine runnig the mq
|
63
|
+
# @param [String] port port the mq is running on
|
64
|
+
def connect(_host, _port)
|
65
|
+
fail 'Method, connect, needs to be implemented'
|
66
|
+
end
|
67
|
+
|
68
|
+
# Connect to the receiving queue
|
69
|
+
# @param [String] queuename name of the receiving queue
|
70
|
+
def subscribe(_queuename)
|
71
|
+
fail 'Method, subscribe, needs to be implemented'
|
72
|
+
end
|
73
|
+
|
74
|
+
# Get next msg from queue
|
75
|
+
def pop
|
76
|
+
fail 'Method, pop, needs to be implemented'
|
77
|
+
end
|
78
|
+
|
79
|
+
# "Commit" the pop
|
80
|
+
def ack
|
81
|
+
fail 'Method, ack, needs to be implemented'
|
82
|
+
end
|
83
|
+
|
84
|
+
# At least called in the Host rescue block, to ensure all network links are
|
85
|
+
# healthy
|
86
|
+
# @param [String] queue_name name of the queue to which the msg should be sent
|
87
|
+
# @param [String] msg msg to be sent
|
88
|
+
def send(queue_name, msg)
|
89
|
+
begin
|
90
|
+
@connection.close
|
91
|
+
rescue
|
92
|
+
puts 'AppResource. An error was raised while closing connection to, ' + @uri.to_s
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'beanstalk-client'
|
2
|
+
require 'rservicebus/MQ'
|
3
|
+
|
4
|
+
module RServiceBus
|
5
|
+
# Beanstalk client implementation.
|
6
|
+
class MQBeanstalk < MQ
|
7
|
+
# Connect to the broker
|
8
|
+
def connect(host, port)
|
9
|
+
port ||= 11_300
|
10
|
+
string = "#{host}:#{port}"
|
11
|
+
|
12
|
+
begin
|
13
|
+
@beanstalk = Beanstalk::Pool.new([string])
|
14
|
+
@max_job_size = @beanstalk.stats['max-job-size']
|
15
|
+
if @max_job_size < 4_194_304
|
16
|
+
puts "***WARNING: Lowest recommended.max-job-size is 4m, current
|
17
|
+
max-job-size, #{@max_job_size.to_f / (1024 * 1024)}m"
|
18
|
+
puts '***WARNING: Set the job size with the -z switch, eg
|
19
|
+
/usr/local/bin/beanstalkd -z 4194304'
|
20
|
+
end
|
21
|
+
rescue StandardError => e
|
22
|
+
puts 'Error connecting to Beanstalk'
|
23
|
+
puts "Host string, #{string}"
|
24
|
+
if e.message == 'Beanstalk::NotConnected'
|
25
|
+
puts '***Most likely, beanstalk is not running. Start beanstalk,
|
26
|
+
and try running this again.'
|
27
|
+
puts "***If you still get this error, check beanstalk is running
|
28
|
+
at, #{string}"
|
29
|
+
else
|
30
|
+
puts e.message
|
31
|
+
puts e.backtrace
|
32
|
+
end
|
33
|
+
abort
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def subscribe(queuename)
|
38
|
+
@beanstalk.watch(queuename)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Get next msg from queue
|
42
|
+
def pop
|
43
|
+
begin
|
44
|
+
@job = @beanstalk.reserve @timeout
|
45
|
+
rescue StandardError => e
|
46
|
+
raise NoMsgToProcess if e.message == 'TIMED_OUT'
|
47
|
+
raise e
|
48
|
+
end
|
49
|
+
@job.body
|
50
|
+
end
|
51
|
+
|
52
|
+
def return_to_queue
|
53
|
+
@job.release
|
54
|
+
end
|
55
|
+
|
56
|
+
def ack
|
57
|
+
@job.delete
|
58
|
+
@job = nil
|
59
|
+
end
|
60
|
+
|
61
|
+
def send(queue_name, msg)
|
62
|
+
if msg.length > @max_job_size
|
63
|
+
puts '***Attempting to send a msg which will not fit on queue.'
|
64
|
+
puts "***Msg size, #{msg.length}, max msg size, #{@max_job_size}."
|
65
|
+
fail JobTooBigError, "Msg size, #{msg.length}, max msg size,
|
66
|
+
#{@max_job_size}"
|
67
|
+
end
|
68
|
+
@beanstalk.use(queue_name)
|
69
|
+
@beanstalk.put(msg)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module RServiceBus
|
2
|
+
# Coordinate Transactions across resources, handlers, and Sagas
|
3
|
+
class ResourceManager
|
4
|
+
# Constructor
|
5
|
+
def initialize(state_manager, saga_storage)
|
6
|
+
@app_resources = {}
|
7
|
+
@current_resources = {}
|
8
|
+
@state_manager = state_manager
|
9
|
+
@saga_storage = saga_storage
|
10
|
+
end
|
11
|
+
|
12
|
+
def add(name, res)
|
13
|
+
@app_resources[name] = res
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_all
|
17
|
+
@app_resources
|
18
|
+
end
|
19
|
+
|
20
|
+
def begin
|
21
|
+
@current_resources = {}
|
22
|
+
@state_manager.begin
|
23
|
+
@saga_storage.begin
|
24
|
+
end
|
25
|
+
|
26
|
+
def get(name)
|
27
|
+
if @current_resources[name].nil?
|
28
|
+
r = @app_resources[name]
|
29
|
+
r._connect
|
30
|
+
r.begin
|
31
|
+
RServiceBus.rlog "Preparing resource: #{name}. Begin"
|
32
|
+
end
|
33
|
+
@current_resources[name] = @app_resources[name]
|
34
|
+
@app_resources[name]
|
35
|
+
end
|
36
|
+
|
37
|
+
def commit(msg_name)
|
38
|
+
@state_manager.commit
|
39
|
+
@saga_storage.commit
|
40
|
+
RServiceBus.rlog "HandlerManager.commitResourcesUsedToProcessMsg,
|
41
|
+
#{msg_name}"
|
42
|
+
@current_resources.each do |k, v|
|
43
|
+
RServiceBus.rlog "Commit resource, #{v.class.name}"
|
44
|
+
v.commit
|
45
|
+
v.finished
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def rollback(msg_name)
|
50
|
+
@saga_storage.rollback
|
51
|
+
RServiceBus.rlog "HandlerManager.rollbackResourcesUsedToProcessMsg,
|
52
|
+
#{msg_name}"
|
53
|
+
@current_resources.each do |k, v|
|
54
|
+
begin
|
55
|
+
RServiceBus.rlog "Rollback resource, #{v.class.name}"
|
56
|
+
v.rollback
|
57
|
+
v.finished
|
58
|
+
rescue StandardError => e1
|
59
|
+
puts "Caught nested exception rolling back, #{v.class.name}, for msg,
|
60
|
+
#{msgName}"
|
61
|
+
puts '****'
|
62
|
+
puts e1.message
|
63
|
+
puts e1.backtrace
|
64
|
+
puts '****'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module RServiceBus
|
2
|
+
# Saga Data
|
3
|
+
class SagaData
|
4
|
+
attr_reader :correlationId, :sagaClassName
|
5
|
+
attr_accessor :finished
|
6
|
+
|
7
|
+
def initialize(saga)
|
8
|
+
@createdat = DateTime.now
|
9
|
+
@correlation_id = UUIDTools::UUID.random_create
|
10
|
+
@saga_class_name = saga.class.name
|
11
|
+
@finished = false
|
12
|
+
|
13
|
+
@hash = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(name, *args, &block)
|
17
|
+
@hash.send(name, *args, &block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module RServiceBus
|
2
|
+
# Saga Manager
|
3
|
+
class SagaManager
|
4
|
+
def initialize(host, resource_manager, saga_storage)
|
5
|
+
@handler = {}
|
6
|
+
@start_with = {}
|
7
|
+
@saga = {}
|
8
|
+
@host = host
|
9
|
+
|
10
|
+
@resource_manager = resource_manager
|
11
|
+
@resource_list_by_saga_name = {}
|
12
|
+
@saga_storage = saga_storage
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_methods_by_prefix(saga, prefix)
|
16
|
+
list = []
|
17
|
+
saga.instance_methods.each do |name|
|
18
|
+
list.push name.to_s.sub(prefix, '') if
|
19
|
+
name.to_s.slice(0, prefix.length) == prefix
|
20
|
+
end
|
21
|
+
|
22
|
+
list
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_start_with_method_names(saga)
|
26
|
+
get_methods_by_prefix(saga, 'StartWith_')
|
27
|
+
end
|
28
|
+
|
29
|
+
# setBusAttributeIfRequested
|
30
|
+
# @param [RServiceBus::Saga] saga
|
31
|
+
def set_bus_attribute_if_requested(saga)
|
32
|
+
if defined?(saga.bus)
|
33
|
+
saga.bus = @host
|
34
|
+
RServiceBus.log 'Bus attribute set for: ' + saga.class.name
|
35
|
+
end
|
36
|
+
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def interrogateSagaForAppResources(saga)
|
41
|
+
RServiceBus.rlog "Checking app resources for: #{saga.class.name}"
|
42
|
+
RServiceBus.rlog "If your attribute is not getting set, check that it
|
43
|
+
is in the 'attr_accessor' list"
|
44
|
+
|
45
|
+
@resource_list_by_saga_name[saga.class.name] = []
|
46
|
+
@resource_manager.get_all.each do |k, v|
|
47
|
+
if saga.class.method_defined?(k)
|
48
|
+
@resource_list_by_saga_name[saga.class.name] << k
|
49
|
+
RServiceBus.log "Resource attribute, #{k}, found for: " +
|
50
|
+
saga.class.name
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
def register_saga(saga)
|
58
|
+
s = saga.new
|
59
|
+
set_bus_attribute_if_requested(s)
|
60
|
+
|
61
|
+
get_start_with_method_names(saga).each do |msg_name|
|
62
|
+
@start_with[msg_name] = [] if @start_with[msg_name].nil?
|
63
|
+
@start_with[msg_name] << s
|
64
|
+
|
65
|
+
RServiceBus.log "Registered, #{saga.name}, to StartWith, #{msg_name}"
|
66
|
+
end
|
67
|
+
|
68
|
+
@saga[saga.name] = s
|
69
|
+
|
70
|
+
interrogate_saga_for_app_resources(s)
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
def prep_saga(saga)
|
75
|
+
return if @resource_list_by_saga_name[saga.class.name].nil?
|
76
|
+
|
77
|
+
@resource_list_by_saga_name[saga.class.name].each do |k, v|
|
78
|
+
saga.instance_variable_set("@#{k}", @resource_manager.get(k).get_resource)
|
79
|
+
RServiceBus.rlog "App resource attribute, #{k}, set for: " + saga.class.name
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def handle(rmsg)
|
84
|
+
@resources_used = {}
|
85
|
+
handled = false
|
86
|
+
msg = rmsg.msg
|
87
|
+
|
88
|
+
RServiceBus.log "SagaManager, started processing, #{msg.class.name}", true
|
89
|
+
unless @start_with[msg.class.name].nil?
|
90
|
+
@start_with[msg.class.name].each do |saga|
|
91
|
+
data = Saga_Data.new(saga)
|
92
|
+
@saga_storage.set(data)
|
93
|
+
|
94
|
+
method_name = "StartWith_#{msg.class.name}"
|
95
|
+
process_msg(saga, data, method_name, msg)
|
96
|
+
|
97
|
+
handled = true
|
98
|
+
end
|
99
|
+
end
|
100
|
+
return handled if handled == true
|
101
|
+
|
102
|
+
return false if rmsg.correlation_id.nil?
|
103
|
+
data = @saga_storage.get(rmsg.correlation_id)
|
104
|
+
return handled if data.nil?
|
105
|
+
method_name = "handle_#{msg.class.name}"
|
106
|
+
saga = @saga[data.saga_class_name]
|
107
|
+
process_msg(saga, data, method_name, msg)
|
108
|
+
|
109
|
+
return true
|
110
|
+
end
|
111
|
+
|
112
|
+
def process_msg(saga, data, methodName, msg)
|
113
|
+
@host.saga_data = data
|
114
|
+
saga.data = data
|
115
|
+
prep_saga(saga)
|
116
|
+
|
117
|
+
if saga.class.method_defined?(method_name)
|
118
|
+
saga.send method_name, msg
|
119
|
+
end
|
120
|
+
|
121
|
+
if data.finished == true
|
122
|
+
@saga_storage.delete data.correlation_id
|
123
|
+
end
|
124
|
+
|
125
|
+
@host.saga_data = nil
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|