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.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +64 -0
  3. data/bin/return_messages_to_source_queue +114 -0
  4. data/bin/rsb_ctl +38 -0
  5. data/bin/rservicebus2 +14 -0
  6. data/bin/rservicebus2-create +107 -0
  7. data/bin/rservicebus2-init +104 -0
  8. data/bin/rservicebus2-transport +16 -0
  9. data/bin/send_empty_message +15 -0
  10. data/lib/rservicebus.rb +59 -0
  11. data/lib/rservicebus/agent.rb +54 -0
  12. data/lib/rservicebus/appresource.rb +65 -0
  13. data/lib/rservicebus/appresource/dir.rb +29 -0
  14. data/lib/rservicebus/appresource/file.rb +8 -0
  15. data/lib/rservicebus/appresource/fluiddb.rb +24 -0
  16. data/lib/rservicebus/appresource_configure.rb +33 -0
  17. data/lib/rservicebus/audit.rb +28 -0
  18. data/lib/rservicebus/circuitbreaker.rb +79 -0
  19. data/lib/rservicebus/config.rb +168 -0
  20. data/lib/rservicebus/cron_manager.rb +76 -0
  21. data/lib/rservicebus/endpointmapping.rb +72 -0
  22. data/lib/rservicebus/errormessage.rb +14 -0
  23. data/lib/rservicebus/handler_loader.rb +162 -0
  24. data/lib/rservicebus/handler_manager.rb +131 -0
  25. data/lib/rservicebus/helper_functions.rb +85 -0
  26. data/lib/rservicebus/host.rb +487 -0
  27. data/lib/rservicebus/message.rb +78 -0
  28. data/lib/rservicebus/message/statisticoutput.rb +7 -0
  29. data/lib/rservicebus/message/subscription.rb +10 -0
  30. data/lib/rservicebus/message/verboseoutput.rb +7 -0
  31. data/lib/rservicebus/monitor.rb +61 -0
  32. data/lib/rservicebus/monitor/csvdir.rb +52 -0
  33. data/lib/rservicebus/monitor/dir.rb +139 -0
  34. data/lib/rservicebus/monitor/dirnotifier.rb +101 -0
  35. data/lib/rservicebus/monitor/message.rb +11 -0
  36. data/lib/rservicebus/monitor/xmldir.rb +11 -0
  37. data/lib/rservicebus/monitor_configure.rb +71 -0
  38. data/lib/rservicebus/mq.rb +98 -0
  39. data/lib/rservicebus/mq/beanstalk.rb +72 -0
  40. data/lib/rservicebus/resource_manager.rb +69 -0
  41. data/lib/rservicebus/saga/base.rb +17 -0
  42. data/lib/rservicebus/saga/data.rb +20 -0
  43. data/lib/rservicebus/saga/manager.rb +128 -0
  44. data/lib/rservicebus/saga_loader.rb +118 -0
  45. data/lib/rservicebus/saga_storage.rb +18 -0
  46. data/lib/rservicebus/saga_storage/dir.rb +87 -0
  47. data/lib/rservicebus/saga_storage/inmemory.rb +37 -0
  48. data/lib/rservicebus/sendat_manager.rb +33 -0
  49. data/lib/rservicebus/sendat_storage.rb +20 -0
  50. data/lib/rservicebus/sendat_storage/file.rb +37 -0
  51. data/lib/rservicebus/sendat_storage/inmemory.rb +20 -0
  52. data/lib/rservicebus/state_manager.rb +30 -0
  53. data/lib/rservicebus/state_storage.rb +18 -0
  54. data/lib/rservicebus/state_storage/dir.rb +66 -0
  55. data/lib/rservicebus/state_storage/inmemory.rb +25 -0
  56. data/lib/rservicebus/statistic_manager.rb +86 -0
  57. data/lib/rservicebus/stats.rb +68 -0
  58. data/lib/rservicebus/subscription_manager.rb +31 -0
  59. data/lib/rservicebus/subscription_storage.rb +39 -0
  60. data/lib/rservicebus/subscription_storage/file.rb +42 -0
  61. data/lib/rservicebus/subscription_storage/redis.rb +69 -0
  62. data/lib/rservicebus/subscription_storage_configure.rb +19 -0
  63. data/lib/rservicebus/test.rb +2 -0
  64. data/lib/rservicebus/test/bus.rb +32 -0
  65. data/lib/rservicebus/transporter.rb +142 -0
  66. data/lib/rservicebus/usermessage/withpayload.rb +10 -0
  67. metadata +184 -0
@@ -0,0 +1,11 @@
1
+ module RServiceBus
2
+ # Monitor Message
3
+ class MonitorMessage
4
+ attr_reader :payload, :uri
5
+
6
+ def initialize(payload, uri)
7
+ @payload = payload
8
+ @uri = uri
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require 'rservicebus/monitor/dir'
2
+ require 'xmlsimple'
3
+
4
+ module RServiceBus
5
+ # Monitor Dir for XML files
6
+ class MonitorXmlDir < MonitorDir
7
+ def process_content(content)
8
+ XmlSimple.xml_in(content)
9
+ end
10
+ end
11
+ end
@@ -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,17 @@
1
+ module RServiceBus
2
+ # Sags Base Class
3
+ class SagaBase
4
+ attr_accessor :data
5
+
6
+ def initialize
7
+ @finished = false
8
+ end
9
+
10
+ def send_timeout(_msg, _milliseconds)
11
+ end
12
+
13
+ def finish
14
+ @data.finished = true
15
+ end
16
+ end
17
+ 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