strum-esb 0.0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 360c4b7cd86f34d2dd3628104474c6948cb926b852c493880b931d0f7a1730e6
4
- data.tar.gz: 963fc92e530b52200a58e205247ded0728e1247aa8c865c69f3aa5d56fe729fa
3
+ metadata.gz: 100cac09566f7c972a3ea3cb7005fc3c57ecc20cc7cb4e159b43dcf4b5d9bc24
4
+ data.tar.gz: dd290413c6ae5f8cc50659a487bc656500c04cd27d289cf13f10eaea14e90343
5
5
  SHA512:
6
- metadata.gz: 9ffa2333d5dbbd263b32c7944acbfe2f82aa9233c8f7e6f2337f2444f134fb88b33ec260e377c1d4126609ad1194f62a24acce30a0cdc34f919f027da62db9a1
7
- data.tar.gz: 740715b0c16c4c2f270f94fd2fca43aea88194f9c0352860b31fdb74758ffafa92cbaefb755f783b6de540473779d48a81a4b45ed50f8bb6270e7e350d3c8126
6
+ metadata.gz: c1a9a87ba8f0207f0de46d08f19229835e29ab844f2053f38a0eb484efc191460d83a6d5e87421d1d4df09152138e753f93705035b4866c6f0ff502b2cffdadf
7
+ data.tar.gz: b3f3d16931dd745a09a7cfbe938b9170c8e4efb4bf511f7de796595ad43ec683cf72c4865cbfe838ee91005b5df1431b32fa12a09fa5426a176a2f99ede62bc3
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,3 @@
1
+ include:
2
+ - project: 'strum-rb/ci-cd'
3
+ file: '/strum-rb/.gitlab-ci.yml'
data/.rubocop.yml CHANGED
@@ -1,5 +1,6 @@
1
1
  AllCops:
2
2
  TargetRubyVersion: 2.6
3
+ NewCops: enable
3
4
 
4
5
  # Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
5
6
  Style/HashSyntax:
data/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+
2
+ # Changelog
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [0.1.1] - 2021-06-01
6
+ ### Added
7
+ - `pre_publish_hooks` to configuration by [@Samuron]
8
+
9
+ ### Fixed
10
+ - bindings for `notice` by [@anton.klyzhka].
11
+ - custom handlers for resource name with `-` by [@anton.klyzhka].
12
+
13
+ ### Changed
14
+ - return `chain` to header and payload for back compatibility by [@anton.klyzhka].
data/Gemfile CHANGED
@@ -1,12 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
5
  # Specify your gem's dependencies in strum-esb.gemspec
4
6
  gemspec
5
7
 
6
8
  gem "bundler", "~> 2.1.4"
7
- gem "rake", "~> 12"
8
9
  gem "rspec", "~> 3"
9
- gem "rubocop", "~> 0.62.0"
10
+ gem "rubocop", "~> 1.15"
11
+ gem "rubocop-rspec", "~> 2.3.0"
10
12
 
11
13
  gem "debase", "~> 0.2.4"
12
- gem "ruby-debug-ide", "~> 0.7.0"
14
+ gem "ruby-debug-ide", "~> 0.7.2"
15
+
data/Gemfile.lock CHANGED
@@ -1,59 +1,74 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- strum-esb (0.0.1)
4
+ strum-esb (0.2.0)
5
5
  bunny (~> 2.15)
6
6
  connection_pool (~> 2.2.2)
7
+ dry-configurable (~> 0.12.1)
7
8
  json (~> 2.3)
8
9
  sneakers (~> 2.12)
9
10
 
10
11
  GEM
11
12
  remote: https://rubygems.org/
12
13
  specs:
13
- amq-protocol (2.3.1)
14
- ast (2.4.0)
15
- bunny (2.15.0)
14
+ amq-protocol (2.3.2)
15
+ ast (2.4.2)
16
+ bunny (2.19.0)
16
17
  amq-protocol (~> 2.3, >= 2.3.1)
17
- concurrent-ruby (1.1.6)
18
- connection_pool (2.2.2)
18
+ sorted_set (~> 1, >= 1.0.2)
19
+ concurrent-ruby (1.1.9)
20
+ connection_pool (2.2.5)
19
21
  debase (0.2.4.1)
20
22
  debase-ruby_core_source (>= 0.10.2)
21
- debase-ruby_core_source (0.10.9)
22
- diff-lcs (1.3)
23
- jaro_winkler (1.5.4)
24
- json (2.3.0)
25
- parallel (1.19.1)
26
- parser (2.7.1.1)
27
- ast (~> 2.4.0)
28
- powerpack (0.1.2)
23
+ debase-ruby_core_source (0.10.12)
24
+ diff-lcs (1.4.4)
25
+ dry-configurable (0.12.1)
26
+ concurrent-ruby (~> 1.0)
27
+ dry-core (~> 0.5, >= 0.5.0)
28
+ dry-core (0.7.1)
29
+ concurrent-ruby (~> 1.0)
30
+ json (2.5.1)
31
+ parallel (1.20.1)
32
+ parser (3.0.1.1)
33
+ ast (~> 2.4.1)
29
34
  rainbow (3.0.0)
30
35
  rake (12.3.3)
31
- rspec (3.9.0)
32
- rspec-core (~> 3.9.0)
33
- rspec-expectations (~> 3.9.0)
34
- rspec-mocks (~> 3.9.0)
35
- rspec-core (3.9.1)
36
- rspec-support (~> 3.9.1)
37
- rspec-expectations (3.9.1)
36
+ rbtree (0.4.4)
37
+ regexp_parser (2.1.1)
38
+ rexml (3.2.5)
39
+ rspec (3.10.0)
40
+ rspec-core (~> 3.10.0)
41
+ rspec-expectations (~> 3.10.0)
42
+ rspec-mocks (~> 3.10.0)
43
+ rspec-core (3.10.1)
44
+ rspec-support (~> 3.10.0)
45
+ rspec-expectations (3.10.1)
38
46
  diff-lcs (>= 1.2.0, < 2.0)
39
- rspec-support (~> 3.9.0)
40
- rspec-mocks (3.9.1)
47
+ rspec-support (~> 3.10.0)
48
+ rspec-mocks (3.10.2)
41
49
  diff-lcs (>= 1.2.0, < 2.0)
42
- rspec-support (~> 3.9.0)
43
- rspec-support (3.9.2)
44
- rubocop (0.62.0)
45
- jaro_winkler (~> 1.5.1)
50
+ rspec-support (~> 3.10.0)
51
+ rspec-support (3.10.2)
52
+ rubocop (1.15.0)
46
53
  parallel (~> 1.10)
47
- parser (>= 2.5, != 2.5.1.1)
48
- powerpack (~> 0.1)
54
+ parser (>= 3.0.0.0)
49
55
  rainbow (>= 2.2.2, < 4.0)
56
+ regexp_parser (>= 1.8, < 3.0)
57
+ rexml
58
+ rubocop-ast (>= 1.5.0, < 2.0)
50
59
  ruby-progressbar (~> 1.7)
51
- unicode-display_width (~> 1.4.0)
52
- ruby-debug-ide (0.7.0)
60
+ unicode-display_width (>= 1.4.0, < 3.0)
61
+ rubocop-ast (1.6.0)
62
+ parser (>= 3.0.1.1)
63
+ rubocop-rspec (2.3.0)
64
+ rubocop (~> 1.0)
65
+ rubocop-ast (>= 1.1.0)
66
+ ruby-debug-ide (0.7.2)
53
67
  rake (>= 0.8.1)
54
- ruby-progressbar (1.10.1)
68
+ ruby-progressbar (1.11.0)
55
69
  serverengine (2.1.1)
56
70
  sigdump (~> 0.2.2)
71
+ set (1.0.1)
57
72
  sigdump (0.2.4)
58
73
  sneakers (2.12.0)
59
74
  bunny (~> 2.14)
@@ -61,8 +76,11 @@ GEM
61
76
  rake (~> 12.3)
62
77
  serverengine (~> 2.1.0)
63
78
  thor
64
- thor (1.0.1)
65
- unicode-display_width (1.4.1)
79
+ sorted_set (1.0.3)
80
+ rbtree
81
+ set (~> 1.0)
82
+ thor (1.1.0)
83
+ unicode-display_width (2.0.0)
66
84
 
67
85
  PLATFORMS
68
86
  ruby
@@ -70,10 +88,10 @@ PLATFORMS
70
88
  DEPENDENCIES
71
89
  bundler (~> 2.1.4)
72
90
  debase (~> 0.2.4)
73
- rake (~> 12)
74
91
  rspec (~> 3)
75
- rubocop (~> 0.62.0)
76
- ruby-debug-ide (~> 0.7.0)
92
+ rubocop (~> 1.15)
93
+ rubocop-rspec (~> 2.3.0)
94
+ ruby-debug-ide (~> 0.7.2)
77
95
  strum-esb!
78
96
 
79
97
  BUNDLED WITH
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # Strum::Esb
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/strum/esb`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ Useful sender RabbitMQ messages and handle them
6
4
 
7
5
  ## Installation
8
6
 
@@ -22,7 +20,80 @@ Or install it yourself as:
22
20
 
23
21
  ## Usage
24
22
 
25
- TODO: Write usage instructions here
23
+ ### Configuration
24
+
25
+ Exchanges can be customized by each message type:
26
+ ```ruby
27
+ Strum::Esb.config.info_exchange = `demo.info`
28
+ Strum::Esb.config.event_exchange = `demo.events`
29
+ Strum::Esb.config.action_exchange = `demo.actions`
30
+ Strum::Esb.config.notice_exchange = `demo.notice`
31
+ ```
32
+
33
+ Before publish hooks allow you to configure custom code that will be able to modify properties of the message that will be published or execute any arbitrary logic
34
+ ```ruby
35
+ Strum::Esb.config.before_publish_hooks << ->(body, properties) { properties[:correlation_id] = "hello world" }
36
+ ```
37
+
38
+ Before handler hooks allow you to inspect raw data before any processing has strated:
39
+ ```ruby
40
+ Strum::Esb.config.before_handler_hooks << ->(deserialized_msg, delivery_info, metadata) do
41
+ puts "We don't even know if msg is valid JSON, this is some text from RabbitMQ"
42
+ puts deserialized_msg
43
+ end
44
+ ```
45
+
46
+ After handler hook allows you to have insight on how handler was executed:
47
+ ```ruby
48
+ Strum::Esb.config.after_handler_hooks << ->(deserialized_msg, delivery_info, metadata, payload, error) do
49
+ puts "Message was deserialized succesfully" if payload
50
+ puts "Error occured" if error
51
+ end
52
+ ```
53
+
54
+
55
+ ### Sending message:
56
+
57
+ ```ruby
58
+ Strum::Esb::Action.call(`payload`, `action`, `resource`)
59
+ ```
60
+
61
+ ```ruby
62
+ Strum::Esb::Event.success(`payload`, `resource`, `*events`)
63
+ Strum::Esb::Event.failure(`payload`, `resource`, `*events`)
64
+ ```
65
+
66
+ ```ruby
67
+ Strum::Esb::Info.call(`payload`, `resource`)
68
+ ```
69
+
70
+ ```ruby
71
+ Strum::Esb::Notice.call(`payload`, `notice`)
72
+ Strum::Esb::Notice.call(`payload`, `notice`, `resource`)
73
+ ```
74
+
75
+ ### Handling message:
76
+
77
+ ```ruby
78
+ require "strum/esb"
79
+
80
+ module Queues
81
+ class Resource
82
+ include Strum::Esb::Handler
83
+
84
+ from_queue "resource-queue",
85
+ bindings: {
86
+ events: %w[user/create user/update],
87
+
88
+ }
89
+
90
+ def handler(payload)
91
+ # code here ...
92
+ end
93
+ end
94
+ end
95
+ ```
96
+
26
97
 
27
98
  ## Development
28
99
 
@@ -32,5 +103,5 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
103
 
33
104
  ## Contributing
34
105
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/strum-esb.
106
+ Bug reports and pull requests are welcome on GitHub at https://code.qpard.com/srtrum/strum-esb.
36
107
 
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
  require "rspec/core/rake_task"
3
5
 
4
6
  RSpec::Core::RakeTask.new(:spec)
5
7
 
6
- task :default => :spec
8
+ task default: :spec
data/bin/console CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require "bundler/setup"
4
5
  require "strum/esb"
@@ -10,11 +11,11 @@ require "strum/esb"
10
11
  # require "pry"
11
12
  # Pry.start
12
13
 
13
- Strum::Esb::Message.rabbit_connection ||= begin
14
- rabbit_connection = Bunny.new
15
- rabbit_connection.start
16
- rabbit_connection
17
- end
14
+ Strum::Esb.config.exchange = "demo.general"
15
+ Strum::Esb.config.info_exchange = "demo.info"
16
+ Strum::Esb.config.event_exchange = "demo.events"
17
+ Strum::Esb.config.action_exchange = "demo.actions"
18
+ Strum::Esb.config.notice_exchange = "demo.notice"
18
19
 
19
20
  require "irb"
20
21
  IRB.start(__FILE__)
@@ -7,8 +7,8 @@ module Strum
7
7
  # Action message
8
8
  class Action < Message
9
9
  class << self
10
- def call(payload, action, resource, exchange: "strum.actions", chain: Thread.current[:chain])
11
- publish(headers: { resource: resource, action: action }, payload: payload, exchange: exchange, chain: chain)
10
+ def call(payload, action, resource, exchange: Strum::Esb.config.action_exchange, **opts)
11
+ publish(headers: { resource: resource, action: action }, payload: payload, exchange: exchange, **opts)
12
12
  end
13
13
  end
14
14
  end
@@ -7,13 +7,16 @@ module Strum
7
7
  # Event message
8
8
  class Event < Message
9
9
  class << self
10
- def call(payload, resource, event, state, exchange:, chain:)
11
- publish(headers: { resource: resource, event: event, state: state }, payload: payload, exchange: exchange, chain: chain)
12
- end
13
-
14
10
  %i[success failure].each do |method_name|
15
- define_method method_name do |payload, resource, *events, exchange: "strum.events", chain: Thread.current[:chain]|
16
- events.each { |event| call(payload, resource, event, method_name, exchange: exchange, chain: chain) }
11
+ define_method method_name do |payload, resource, event, exchange: Strum::Esb.config.event_exchange, **opts|
12
+ publish(headers: {
13
+ resource: resource,
14
+ event: event,
15
+ state: method_name
16
+ },
17
+ payload: payload,
18
+ exchange: exchange,
19
+ **opts)
17
20
  end
18
21
  end
19
22
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Strum
4
+ module Esb
5
+ class Functions
6
+ class << self
7
+ def action_explain(source)
8
+ exchange, resource_action = source.include?(":") ? source.split(":") : [Strum::Esb.config.action_exchange, source]
9
+ action, resource = resource_action.split("/")
10
+ [exchange, action, resource]
11
+ end
12
+
13
+ def event_explain(source)
14
+ exchange, resource_event = source.include?(":") ? source.split(":") : [Strum::Esb.config.event_exchange, source]
15
+ resource, event, state = resource_event.split("/")
16
+ [exchange, resource, event, state || "success"]
17
+ end
18
+
19
+ def notice_explain(source)
20
+ exchange, resource_notice = source.include?(":") ? source.split(":") : [Strum::Esb.config.notice_exchange, source]
21
+ resource, notice = resource_notice.split("/")
22
+ [exchange, resource, notice]
23
+ end
24
+
25
+ def info_explain(source)
26
+ source.include?(":") ? source.split(":") : [Strum::Esb.config.info_exchange, source]
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "json"
4
+ require "strum/esb/functions"
4
5
 
5
6
  module Strum
6
7
  module Esb
@@ -10,11 +11,31 @@ module Strum
10
11
  base.class_eval do
11
12
  include Sneakers::Worker
12
13
  end
14
+ base.extend ClassMethods
13
15
  end
14
16
 
15
- def work_with_params(deserialized_msg, _delivery_info, metadata)
16
- notice_data = JSON.parse(deserialized_msg)
17
+ module ClassMethods
18
+ def bind_to(queue, message_type, message_binding, handler = nil)
19
+ bindings ||= (queue_opts && queue_opts[:bindings]) || {}
20
+ bindings[message_type] ||= []
21
+ bindings[message_type] << message_binding
22
+ from_queue queue, bindings: bindings
23
+ _, *msg = Strum::Esb::Functions.public_send("#{message_type}_explain", message_binding)
24
+ @handlers ||= {}
25
+ params = msg.map{ |param| param&.to_s.gsub(/[^a-zA-Z0-9]/, "_")&.downcase }
26
+ handler_key = ([message_type] + params).join("-")
27
+ @handlers[handler_key] = handler.to_s if handler
28
+ end
29
+
30
+ def handlers
31
+ @handlers || {}
32
+ end
33
+ end
34
+
35
+ def work_with_params(deserialized_msg, delivery_info, metadata)
36
+ Strum::Esb.config.before_handler_hooks.each { |hook| hook.call(deserialized_msg, delivery_info, metadata) }
17
37
 
38
+ payload = JSON.parse(deserialized_msg)
18
39
  snake_case_modify = ->(string) { string.nil? ? nil : string&.to_s.gsub(/[^a-zA-Z0-9]/, "_")&.downcase }
19
40
  parse_header = ->(string) { metadata[:headers] && metadata[:headers][string] }
20
41
  header = parse_header >> snake_case_modify
@@ -24,47 +45,87 @@ module Strum
24
45
  event = header.call("event")
25
46
  state = header.call("state")
26
47
  info = header.call("info")
27
- chain = header.call("chain")
28
48
  notice = header.call("notice")
29
- Thread.current[:chain] = chain
49
+ Thread.current[:chain] = header.call("chain")
50
+ Thread.current[:pipeline] = header.call("pipeline")
51
+ Thread.current[:pipeline_id] = header.call("pipeline-id")
52
+
53
+ after_headers_hook
30
54
 
31
55
  methods_names = if action
32
- %W[action_#{action}_#{resource} action_handler]
56
+ action_handler_methods(action, resource)
33
57
  elsif event
34
- result = %W[event_#{resource}_#{event}_#{state}]
35
- result << "event_#{resource}_#{event}" if state.eql?("success")
36
- result << "event_handler"
37
- result
58
+ event_handler_methods(resource, event, state)
38
59
  elsif info
39
- %W[info_#{info} info_handler]
60
+ info_handler_methods(info)
40
61
  elsif notice
41
- result = []
42
- result << "notice_#{resource}_#{notice}" if resource
43
- result << "notice_#{notice}"
44
- result << "notice_handler"
45
- result
46
- end
62
+ notice_handler_methods(resource, notice)
63
+ end
47
64
 
48
65
  method_name = ([*methods_names] << "handler").find { |n| respond_to?(n, include_all: true) }
49
66
 
50
67
  unless method_name
51
- logger.debug "Handler not found. Message rejected #{metadata[:headers]} with payload #{notice_data}"
68
+ logger.error "Handler not found. Message rejected #{metadata[:headers]} with payload #{payload}"
52
69
  return reject!
53
70
  end
54
71
 
72
+ error = nil
55
73
  method_params = method(method_name)
56
74
  .parameters
57
75
  .map { |param| _, param_name = param; param_name }
58
- .then { |m| m & %I[action resource event state chain info] }
76
+ .then { |m| m & %I[action resource event state info chain] }
59
77
  handler_params = method_params.each_with_object({}) { |i, res| res[i] = eval(i.to_s); }
60
- logger.debug("Handler #{method_name} found. Payload: #{notice_data}")
61
- handler_params.count.positive? ? send(method_name, notice_data, handler_params) : send(method_name, notice_data)
62
- logger.debug("Handler #{method_name} executed")
78
+ logger.info("Handler #{method_name} found. Payload: #{payload}")
79
+ handler_params.count.positive? ? send(method_name, payload, handler_params) : send(method_name, payload)
80
+ logger.info("Handler #{method_name} executed")
63
81
  ack!
64
82
  rescue StandardError => e
83
+ error = e
65
84
  logger.error e
66
85
  reject!
86
+ ensure
87
+ Strum::Esb.config.after_handler_hooks.each { |hook| hook.call(deserialized_msg, delivery_info, metadata, payload, error) }
67
88
  end
89
+
90
+ def after_headers_hook; end
91
+
92
+ private
93
+
94
+ def action_handler_methods(action, resource)
95
+ if (custom_handler = self.class.handlers[["action", action, resource].join("-")])
96
+ %W[#{custom_handler} action_#{action}_#{resource} action_handler]
97
+ else
98
+ %W[action_#{action}_#{resource} action_handler]
99
+ end
100
+ end
101
+
102
+ def event_handler_methods(resource, event, state)
103
+ result = []
104
+ custom_handler = self.class.handlers[["event", resource, event, state].join("-")]
105
+ result << custom_handler if custom_handler
106
+ result << "event_#{resource}_#{event}_#{state}"
107
+ result << "event_#{resource}_#{event}" if state.eql?("success")
108
+ result << "event_handler"
109
+ result
110
+ end
111
+
112
+ def info_handler_methods(info)
113
+ if (custom_handler = self.class.handlers[["info", info].join("-")])
114
+ %W[#{custom_handler} info_#{info} info_handler]
115
+ else
116
+ %W[info_#{info} info_handler]
117
+ end
118
+ end
119
+
120
+ def notice_handler_methods(resource, notice)
121
+ custom_handler = self.class.handlers[["notice", resource, notice].join("-")]
122
+ result = []
123
+ result << custom_handler if custom_handler
124
+ result << "notice_#{resource}_#{notice}" if resource
125
+ result << "notice_#{notice}"
126
+ result << "notice_handler"
127
+ result
128
+ end
68
129
  end
69
130
  end
70
- end
131
+ end
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "message"
3
+ require "strum/esb/message"
4
4
 
5
5
  module Strum
6
6
  module Esb
7
7
  # Action message
8
8
  class Info < Message
9
9
  class << self
10
- def call(payload, resource, exchange: "strum.info", chain: Thread.current[:chain])
11
- publish(headers: { info: resource }, payload: payload, exchange: exchange, chain: chain)
10
+ def call(payload, resource, exchange: Strum::Esb.config.info_exchange, **opts)
11
+ publish(headers: { info: resource }, payload: payload, exchange: exchange, **opts)
12
12
  end
13
13
  end
14
14
  end
@@ -5,25 +5,26 @@ module Strum
5
5
  # Strum Message
6
6
  class Message
7
7
  class << self
8
- attr_accessor :rabbit_connection
8
+ def publish(exchange:, headers:, payload:)
9
+ rabbit_exchange ||= Strum::Esb.config.rabbit_channel_pool.with { |rabbit_channel| rabbit_channel.headers(exchange, durable: true) }
10
+ properties = {
11
+ headers: headers,
12
+ content_type: "application/json"
13
+ }
9
14
 
10
- def publish(exchange:, headers:, payload:, chain:)
11
- rabbit_exchange ||= Strum::Esb::Message.rabbit_channel.headers(exchange, durable: true)
12
- if chain
15
+ Strum::Esb.config.before_publish_hooks.each { |hook| hook.call(payload, properties) }
16
+
17
+ properties[:headers] = {} unless properties[:headers].is_a?(Hash)
18
+ properties[:headers]["pipeline"] ||= Thread.current[:pipeline] if Thread.current[:pipeline]
19
+ properties[:headers]["pipeline-id"] ||= Thread.current[:pipeline_id] if Thread.current[:pipeline_id]
20
+ if (chain = Thread.current[:chain])
13
21
  payload["chain"] ||= chain
14
22
  headers["chain"] ||= chain
15
23
  end
16
- rabbit_exchange.publish(payload.to_json, headers: headers, content_type: "application/json")
17
- end
18
-
19
- def rabbit_channel
20
- @rabbit_channel ||= begin
21
- raise "Strum::Esb::Message.rabbit_connection must be setup" unless rabbit_connection
22
- rabbit_connection.create_channel
23
- end
24
+
25
+ rabbit_exchange.publish(payload.to_json, **properties)
24
26
  end
25
27
  end
26
28
  end
27
29
  end
28
30
  end
29
-
@@ -7,10 +7,10 @@ module Strum
7
7
  # Notice message
8
8
  class Notice < Message
9
9
  class << self
10
- def call(payload, notice, resource = nil, exchange: "strum.notice", chain: Thread.current[:chain])
10
+ def call(payload, notice, resource = nil, exchange: Strum::Esb.config.notice_exchange, **opts)
11
11
  headers = { notice: notice }
12
12
  headers[:resource] = resource if resource
13
- publish(headers: headers, payload: payload, exchange: exchange, chain: chain)
13
+ publish(headers: headers, payload: payload, exchange: exchange, **opts)
14
14
  end
15
15
  end
16
16
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Strum
2
4
  module Esb
3
- VERSION = "0.0.1"
5
+ VERSION = "0.2.0"
4
6
  end
5
7
  end
data/lib/strum/esb.rb CHANGED
@@ -1,36 +1,61 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "strum/esb/version"
2
4
 
3
5
  require "json"
4
6
  require "bunny"
5
7
  require "sneakers"
6
- require_relative "patch/sneakers/queue_patch"
7
- require_relative "esb/handler"
8
- require_relative "esb/message"
9
- require_relative "esb/action"
10
- require_relative "esb/event"
11
- require_relative "esb/notice"
12
- require_relative "esb/info"
8
+ require "connection_pool"
9
+ require "etc"
10
+ require "strum/patch/sneakers/queue_patch"
11
+ require "strum/esb/handler"
12
+ require "strum/esb/message"
13
+ require "strum/esb/action"
14
+ require "strum/esb/event"
15
+ require "strum/esb/notice"
16
+ require "strum/esb/info"
17
+ require "dry/configurable"
13
18
 
14
19
  module Strum
15
20
  module Esb
21
+ extend Dry::Configurable
22
+
23
+ setting :sneakers_workers, ENV.fetch("SNEAKERS_WORKERS", 1)
24
+ setting :exchange, "strum.general"
25
+ setting :info_exchange, "strum.info"
26
+ setting :event_exchange, "strum.events"
27
+ setting :action_exchange, "strum.actions"
28
+ setting :notice_exchange, "strum.notice"
29
+ setting :rabbit_channel_pool, begin
30
+ ConnectionPool.new(size: 5, timeout: 5) do
31
+ rabbit_connection = Bunny.new
32
+ rabbit_connection.start
33
+ rabbit_connection.create_channel
34
+ end
35
+ end
36
+ setting :before_fork_hooks, []
37
+ setting :after_fork_hooks, []
38
+ setting :before_publish_hooks, []
39
+ setting :before_handler_hooks, []
40
+ setting :after_handler_hooks, []
41
+
42
+ Strum::Esb.config.before_fork_hooks << proc { DB.disconnect } if defined?(DB)
43
+
44
+ Strum::Esb.config.after_fork_hooks << proc do
45
+ end
46
+
16
47
  class Error < StandardError; end
17
48
 
18
49
  Sneakers.configure(
19
- log: STDOUT,
20
- hooks: {
21
- before_fork: lambda { DB.disconnect if defined?(DB) },
22
- after_fork: lambda do
23
- Strum::Esb::Message.rabbit_connection ||= begin
24
- rabbit_connection = Bunny.new
25
- rabbit_connection.start
26
- rabbit_connection
27
- end
28
- end
29
- },
30
- exchange: "strum.general",
31
- exchange_type: "headers"
50
+ log: $stdout,
51
+ workers: Strum::Esb.config.sneakers_workers,
52
+ hooks: {
53
+ before_fork: -> { Strum::Esb.config.before_fork_hooks.each(&:call) },
54
+ after_fork: -> { Strum::Esb.config.after_fork_hooks.each(&:call) }
55
+ },
56
+ exchange: Strum::Esb.config.exchange,
57
+ exchange_type: "headers"
32
58
  )
33
59
  Sneakers.logger.level = Logger::INFO
34
-
35
60
  end
36
61
  end
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "sneakers/queue"
4
+ require "strum/esb/functions"
4
5
 
5
6
  module QueuePatch
6
7
  def subscribe(worker)
7
8
  if @opts[:bindings]
8
- qiwa_subscribe(worker)
9
+ strum_subscribe(worker)
9
10
  elsif @opts[:header_bindings]
10
11
  header_subscribe(worker)
11
12
  else
@@ -17,93 +18,89 @@ module QueuePatch
17
18
  # actions: "get/account",
18
19
  # events: %w[account/update account/delete],
19
20
  # infos: "account"
21
+ # pipeline: {
22
+ # name: "pipeline-name",
23
+ # actions: "get/account",
24
+ # events: %w[account/update account/delete],
25
+ # infos: "account"
26
+ # }
20
27
  # }
21
- def qiwa_subscribe(worker)
28
+
29
+ def strum_subscribe(worker)
22
30
  @opts[:header_bindings] = []
23
31
  actions_subscribes([*(@opts[:bindings][:actions] || @opts[:bindings][:action])])
24
32
  events_subscribes([*(@opts[:bindings][:events] || @opts[:bindings][:event])])
25
33
  infos_subscribes([*(@opts[:bindings][:infos] || @opts[:bindings][:info])])
26
34
  notices_subscribes([*(@opts[:bindings][:notices] || @opts[:bindings][:notice])])
35
+ pipeline_subscribes(@opts[:bindings][:pipeline] || @opts[:bindings][:pipelines])
27
36
  header_subscribe(worker)
28
37
  end
29
38
 
30
- def actions_subscribes(actions)
31
- actions.each do |_action|
32
- exchange, resource_action = _action.split(":")
33
- if resource_action.nil?
34
- resource_action = exchange
35
- exchange = "strum.actions"
36
- end
37
- raise StandardError "binding format must be a `exchange:action/resource`" unless exchange && resource_action
39
+ def pipeline_subscribes(pipelines)
40
+ return if pipelines.nil?
41
+
42
+ actions_subscribes([*(pipelines[:actions] || pipelines[:action])], pipeline: pipelines[:name])
43
+ events_subscribes([*(pipelines[:events] || pipelines[:event])], pipeline: pipelines[:name])
44
+ infos_subscribes([*(pipelines[:infos] || pipelines[:info])], pipeline: pipelines[:name])
45
+ notices_subscribes([*(pipelines[:notices] || pipelines[:notice])], pipeline: pipelines[:name])
46
+ end
38
47
 
39
- action, resource = resource_action.split("/")
40
- raise StandardError "binding format must be a `exchange:action/resource`" unless resource && action
48
+ def actions_subscribes(actions, **custom_headers)
49
+ actions.each do |_action|
50
+ exchange, action, resource = Strum::Esb::Functions.action_explain(_action)
51
+ raise StandardError "action binding format must be `exchange:action/resource`" unless resource && action
41
52
 
42
53
  @opts[:header_bindings] << {
43
- exchange: exchange,
44
- arguments: {
45
- action: action,
46
- resource: resource
47
- }
54
+ exchange: exchange,
55
+ arguments: {
56
+ action: action,
57
+ resource: resource
58
+ }.merge(custom_headers)
48
59
  }
49
60
  end
50
61
  end
51
62
 
52
- def events_subscribes(events)
63
+ def events_subscribes(events, **custom_headers)
53
64
  events.each do |_event|
54
- exchange, resource_event = _event.split(":")
55
- if resource_event.nil?
56
- resource_event = exchange
57
- exchange = "strum.events"
58
- end
59
- raise StandardError "binding format must be `exchange:resource/event{/state}`" unless exchange && resource_event
60
-
61
- resource, event, state = resource_event.split("/")
65
+ exchange, resource, event, state = Strum::Esb::Functions.event_explain(_event)
62
66
  raise StandardError "binding format must be `exchange:resource/event{/state}`" unless resource && event
63
67
 
64
68
  @opts[:header_bindings] << {
65
- exchange: exchange,
66
- arguments: {
67
- resource: resource,
68
- event: event,
69
- state: state || "success"
70
- }
69
+ exchange: exchange,
70
+ arguments: {
71
+ resource: resource,
72
+ event: event,
73
+ state: state
74
+ }.merge(custom_headers)
71
75
  }
72
76
  end
73
77
  end
74
78
 
75
- def infos_subscribes(infos)
79
+ def infos_subscribes(infos, **custom_headers)
76
80
  infos.each do |_info|
77
- exchange, resource = _info.split(":")
78
- if resource.nil?
79
- resource = exchange
80
- exchange = "strum.info"
81
- end
82
- raise StandardError "binding format must be a `exchange:resource`" unless exchange && resource
81
+ exchange, resource = Strum::Esb::Functions.info_explain(_info)
82
+ raise StandardError "info binding format must be a `exchange:resource`" unless resource
83
83
 
84
84
  @opts[:header_bindings] << {
85
- exchange: exchange,
86
- arguments: {
87
- info: resource
88
- }
85
+ exchange: exchange,
86
+ arguments: {
87
+ info: resource
88
+ }.merge(custom_headers)
89
89
  }
90
90
  end
91
91
  end
92
92
 
93
- def notices_subscribes(notices)
94
- notices.each do |_info|
95
- exchange, resource = _info.split(":")
96
- if resource.nil?
97
- resource = exchange
98
- exchange = "strum.info"
99
- end
100
- raise StandardError "binding format must be a `exchange:resource`" unless exchange && resource
93
+ def notices_subscribes(notices, **custom_headers)
94
+ notices.each do |_notice|
95
+ exchange, resource, notice = Strum::Esb::Functions.notice_explain(_notice)
96
+ raise StandardError "notice binding format must be a `exchange:resource`" unless resource
101
97
 
102
98
  @opts[:header_bindings] << {
103
- exchange: exchange,
104
- arguments: {
105
- notice: resource
106
- }
99
+ exchange: exchange,
100
+ arguments: {
101
+ notice: notice,
102
+ resource: resource
103
+ }.merge(custom_headers)
107
104
  }
108
105
  end
109
106
  end
@@ -128,7 +125,11 @@ module QueuePatch
128
125
  header_bindings.each do |header_binding|
129
126
  exchange_name = header_binding[:exchange] || @opts[:exchange]
130
127
  exchange = @channel.exchange(exchange_name, @opts[:exchange_options].merge(type: :headers))
131
- queue.bind(exchange, arguments: { "x-match": :all }.merge(header_binding[:arguments]))
128
+ queue.bind(exchange,
129
+ arguments: {}.tap do |args|
130
+ args["x-match"] = :all
131
+ end
132
+ .merge(header_binding[:arguments]))
132
133
  end
133
134
 
134
135
  handler = handler_klass.new(@channel, queue, worker.opts)
@@ -140,6 +141,8 @@ module QueuePatch
140
141
  end
141
142
  end
142
143
 
143
- class Sneakers::Queue
144
- prepend QueuePatch
144
+ module Sneakers
145
+ class Queue
146
+ prepend QueuePatch
147
+ end
145
148
  end
data/strum-esb.gemspec CHANGED
@@ -1,4 +1,6 @@
1
- require_relative 'lib/strum/esb/version'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/strum/esb/version"
2
4
 
3
5
  Gem::Specification.new do |spec|
4
6
  spec.name = "strum-esb"
@@ -8,18 +10,18 @@ Gem::Specification.new do |spec|
8
10
 
9
11
  spec.summary = "Publish and subscribe rabbitMQ messages"
10
12
  spec.description = "Publish and subscribe rabbitMQ messages"
11
- spec.homepage = "https://code.qpard.com/strum/strum-esb"
12
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
13
+ spec.homepage = "https://gitlab.com/strum-rb/strum-esb"
14
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
13
15
 
14
16
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
15
17
 
16
18
  spec.metadata["homepage_uri"] = spec.homepage
17
- spec.metadata["source_code_uri"] = "https://code.qpard.com/strum/strum-esb"
18
- spec.metadata["changelog_uri"] = "https://code.qpard.com/strum/strum-esb/CHANGELOG.md"
19
+ spec.metadata["source_code_uri"] = "https://gitlab.com/strum-rb/strum-esb"
20
+ spec.metadata["changelog_uri"] = "https://gitlab.com/strum-rb/strum-esb/CHANGELOG.md"
19
21
 
20
22
  # Specify which files should be added to the gem when it is released.
21
23
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
23
25
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
26
  end
25
27
  spec.bindir = "exe"
@@ -28,6 +30,7 @@ Gem::Specification.new do |spec|
28
30
 
29
31
  spec.add_dependency "bunny", "~> 2.15"
30
32
  spec.add_dependency "connection_pool", "~> 2.2.2"
33
+ spec.add_dependency "dry-configurable", "~> 0.12.1"
31
34
  spec.add_dependency "json", "~> 2.3"
32
35
  spec.add_dependency "sneakers", "~> 2.12"
33
36
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strum-esb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Serhiy Nazarov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-04-16 00:00:00.000000000 Z
11
+ date: 2021-08-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bunny
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 2.2.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: dry-configurable
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.12.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.12.1
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: json
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -74,10 +88,11 @@ extensions: []
74
88
  extra_rdoc_files: []
75
89
  files:
76
90
  - ".gitignore"
91
+ - ".gitlab-ci.yml"
77
92
  - ".rspec"
78
93
  - ".rubocop.yml"
79
- - ".ruby-version"
80
94
  - ".travis.yml"
95
+ - CHANGELOG.md
81
96
  - Gemfile
82
97
  - Gemfile.lock
83
98
  - README.md
@@ -87,6 +102,7 @@ files:
87
102
  - lib/strum/esb.rb
88
103
  - lib/strum/esb/action.rb
89
104
  - lib/strum/esb/event.rb
105
+ - lib/strum/esb/functions.rb
90
106
  - lib/strum/esb/handler.rb
91
107
  - lib/strum/esb/info.rb
92
108
  - lib/strum/esb/message.rb
@@ -94,13 +110,13 @@ files:
94
110
  - lib/strum/esb/version.rb
95
111
  - lib/strum/patch/sneakers/queue_patch.rb
96
112
  - strum-esb.gemspec
97
- homepage: https://code.qpard.com/strum/strum-esb
113
+ homepage: https://gitlab.com/strum-rb/strum-esb
98
114
  licenses: []
99
115
  metadata:
100
116
  allowed_push_host: https://rubygems.org
101
- homepage_uri: https://code.qpard.com/strum/strum-esb
102
- source_code_uri: https://code.qpard.com/strum/strum-esb
103
- changelog_uri: https://code.qpard.com/strum/strum-esb/CHANGELOG.md
117
+ homepage_uri: https://gitlab.com/strum-rb/strum-esb
118
+ source_code_uri: https://gitlab.com/strum-rb/strum-esb
119
+ changelog_uri: https://gitlab.com/strum-rb/strum-esb/CHANGELOG.md
104
120
  post_install_message:
105
121
  rdoc_options: []
106
122
  require_paths:
@@ -109,14 +125,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
109
125
  requirements:
110
126
  - - ">="
111
127
  - !ruby/object:Gem::Version
112
- version: 2.3.0
128
+ version: 2.6.0
113
129
  required_rubygems_version: !ruby/object:Gem::Requirement
114
130
  requirements:
115
131
  - - ">="
116
132
  - !ruby/object:Gem::Version
117
133
  version: '0'
118
134
  requirements: []
119
- rubygems_version: 3.1.2
135
+ rubygems_version: 3.1.6
120
136
  signing_key:
121
137
  specification_version: 4
122
138
  summary: Publish and subscribe rabbitMQ messages
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 2.7.0