rservicebus2 0.0.1

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