harmoniser 0.4.0 → 0.6.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: b1feaead73df2956797f89d33ed45a3316cf5191852946c1b0d3cbe2e2284f18
4
- data.tar.gz: 6ba7ae634d24a012d4243d392d4299a9fd88a35af5df1251efec24bb4817ce9c
3
+ metadata.gz: 4410b741fa891c42db5f51dc48889768859a9a84a3eed3676fc35f0aaeb8cca1
4
+ data.tar.gz: c6af823a40e9b007f93a347e84ad44aee26dea0e10464fc608c116db7185ec19
5
5
  SHA512:
6
- metadata.gz: 9cfcdeec3f6e205c9301d5f2142cd8e7fee0723ed5950fdf1bd12a704f1cc29ecf971e39c75ef7ace071ea577a37f45a874c4016a63c561d25c3e206f1fb0e6f
7
- data.tar.gz: 45b409fb2bfa3ec1752101915fad8f52ccf1e5a5ea1402e23ee6fc062e952fbdb78a16015f77bc2ef2ddafda04859eb23d0e9c8c9cef06a9675fe0c44e81f5d5
6
+ metadata.gz: d843cfe2d70c4ad95cfbe1ce592b7691c057840a191fb7838670eb68205a44549fd7b8e83ff75c2f7888d5c303903f357b93f64c1e37cd5ec342ebb17553051c
7
+ data.tar.gz: 331c5f2133c0e291581ae3f14be398dac07df8adbc43ad72de798171346380f28a084988ff0215922c12783c6e28ec93640dada3ee9aa096ca63ba43a08d2ee3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.6.0] - 2023-12-30
4
+
5
+ ### Added
6
+ - Create a channel for each class including Harmoniser::Publisher or Harmoniser::Subscriber. A mutex in the context of the class including Publisher or Subscriber modules control access to the resources created as well as guarantees safe publication under multi-thread process.
7
+ - Introduce broadcast and unicast examples.
8
+ - Amend specs to wipe out RabbitMQ resources created during spec execution.
9
+
10
+ ### Changed
11
+ - Honour verbose option regardless of the environment configuration set. For instance, for non-production environment, verbose is no longer verbose set by default.
12
+
13
+ ## [0.5.0] - 2023-12-20
14
+
15
+ ### Added
16
+ - Setup at_exit hook to be executed when Harmoniser exits for an opened RabbitMQ connection
17
+ - Add defaults to Bunny::Session for timeouts and recovery attempts
18
+ - Fix boot up problems for payments application example
19
+ - Perform refactoring of internals such as slimming down Configuration
20
+
3
21
  ## [0.4.0] - 2023-12-07
4
22
 
5
23
  ### Added
data/README.md CHANGED
@@ -51,7 +51,7 @@ end
51
51
  MyPublisher.publish({ salute: "Hello World!" }.to_json, routing_key: "my_resource.foo.bar")
52
52
  ```
53
53
 
54
- The code above assumes that the exchange is already defined. We'd like to emphasize that defining RabbitMQ topology (exchanges, queues and binding) should be performed outside of the class whose role is purely focused on publishing. See more details about how to define the topology [here](examples/multicast.rb#L9-L18).
54
+ The code above assumes that the exchange is already defined. We'd like to emphasize that defining RabbitMQ topology (exchanges, queues and binding) should be performed outside of the class whose role is purely focused on publishing. See more details about how to define the topology [here](examples/multicast.rb#L11-L19).
55
55
 
56
56
  ### RabbitMQ
57
57
 
@@ -78,19 +78,10 @@ Harmoniser server is a process specifically dedicated to run Subscribers that ar
78
78
  class MySubscriber
79
79
  include Harmoniser::Subscriber
80
80
  harmoniser_subscriber queue_name: "my_queue"
81
-
82
- class << self
83
- def on_delivery(delivery_info, properties, payload)
84
- Harmoniser.logger.info({
85
- body: "message received",
86
- payload: payload
87
- }.to_json)
88
- end
89
- end
90
81
  end
91
82
  ```
92
83
 
93
- The code above assumes that the queue and its binding to an exchange are already defined. You can see more details about how this is specified [here](examples/multicast.rb#L9-L18).
84
+ The code above assumes that the queue and its binding to an exchange are already defined. You can see more details about how this is specified [here](examples/multicast.rb#L11-L19).
94
85
 
95
86
  In order for the subscribers to receive messages from a queue, you should spin up a dedicated Ruby process like following:
96
87
 
@@ -123,7 +114,6 @@ You can also shell into the running container by executing `$ make shell` and fr
123
114
 
124
115
  - [ ] Issue: Reopen memoized Channel in the context of the class that are included. There are scenarios for which the channel gets closed, for instance Precondition Failed when checking an exchange declaration.
125
116
  - [ ] Chore: Introduce simplecov gem for code coverage.
126
- - [ ] Feature: Add sensible defaults for Session options like heartbeat, timeout, recovery_completed or recovery_attempt_started.
127
117
  - [ ] Feature: Add default `on_return` handler as well as permitting the definition of on_return method to be called anytime a published message gets returned.
128
118
  - [ ] Feature: Introduce capability of configuring number of threads for queue consuming at the CLI.
129
119
 
data/docs/cli.md CHANGED
@@ -17,4 +17,4 @@ The `environment` is automatically inferred from the environment variables `RAIL
17
17
 
18
18
  The `require` is by default pointing at `.`, which means that this option when configured under a Rails application, might be ignored. Since Ruby is not Rails only, you can certainly specify the location path of your Ruby file that will be used to load the classes including Harmoniser::Subscriber. In contrast, if a path to a directory is passed, Harmoniser assumes that `./config/environment.rb` lives within the folder passed as option.
19
19
 
20
- The `verbose` option, when passed, sets the severity of Harmoniser logs to `debug` being able to see fine-grained details of things like RabbitMQ interactions happening or messages published into exchanges. By default, the verbosity is disabled to prevent your production environment to be flooded with unnecessary logs, however if the environment is not set to `production`, the severity of the logs is `debug` mode too.
20
+ The `verbose` option, when passed, sets the severity of Harmoniser logs to `debug` being able to see fine-grained details of things like RabbitMQ interactions happening or messages published into exchanges. By default, the verbosity is disabled to prevent your environment to be flooded with unnecessary logs.
@@ -46,19 +46,17 @@ module Harmoniser
46
46
  end
47
47
 
48
48
  def run
49
- launcher = Launcher.new
50
- launcher.start
49
+ Launcher
50
+ .new(configuration: configuration, logger: logger)
51
+ .start
51
52
 
52
53
  while @read_io.wait_readable
53
54
  signal = @read_io.gets.strip
54
55
  handle_signal(signal)
55
56
  end
56
57
  rescue Interrupt
57
- logger.info("Shutting down!")
58
- launcher.stop
59
58
  @write_io.close
60
59
  @read_io.close
61
- logger.info("Bye!")
62
60
  exit(0)
63
61
  end
64
62
 
@@ -20,6 +20,6 @@ module Harmoniser
20
20
  @configuration ||= Configuration.new
21
21
  end
22
22
 
23
- def_delegators :configuration, :logger, :connection
23
+ def_delegators :configuration, :connection, :connection?
24
24
  end
25
25
  end
@@ -1,33 +1,20 @@
1
1
  require "forwardable"
2
- require "logger"
3
- require "harmoniser/connection"
2
+ require "harmoniser/connectable"
4
3
  require "harmoniser/topology"
5
4
  require "harmoniser/options"
6
5
 
7
6
  module Harmoniser
8
7
  class Configuration
9
8
  extend Forwardable
9
+ include Connectable
10
10
 
11
- DEFAULT_CONNECTION_OPTS = {
12
- connection_name: "harmoniser@#{VERSION}",
13
- host: "127.0.0.1",
14
- password: "guest",
15
- port: 5672,
16
- tls_silence_warnings: true,
17
- username: "guest",
18
- verify_peer: false,
19
- vhost: "/"
20
- }
21
- MUTEX = Mutex.new
22
-
23
- attr_reader :connection_opts, :logger, :options
11
+ attr_reader :logger, :options
24
12
  def_delegators :options, :environment, :require, :verbose
25
13
 
26
14
  def initialize
27
- @logger = Logger.new($stdout, progname: "harmoniser@#{VERSION}")
15
+ @logger = Harmoniser.logger
28
16
  @options = Options.new(**default_options)
29
17
  set_logger_severity
30
- @connection_opts = DEFAULT_CONNECTION_OPTS.merge({logger: @logger})
31
18
  @topology = Topology.new
32
19
  end
33
20
 
@@ -37,20 +24,6 @@ module Harmoniser
37
24
  yield(@topology)
38
25
  end
39
26
 
40
- def connection
41
- MUTEX.synchronize do
42
- @connection ||= Connection.new(connection_opts)
43
- @connection.start unless @connection.open?
44
- @connection
45
- end
46
- end
47
-
48
- def connection_opts=(opts)
49
- raise TypeError, "opts must be a Hash object" unless opts.is_a?(Hash)
50
-
51
- @connection_opts = connection_opts.merge(opts)
52
- end
53
-
54
27
  def options_with(**)
55
28
  @options = options.with(**)
56
29
  set_logger_severity
@@ -67,11 +40,7 @@ module Harmoniser
67
40
  end
68
41
 
69
42
  def set_logger_severity
70
- @logger.level = if @options.production?
71
- @options.verbose? ? Logger::DEBUG : Logger::INFO
72
- else
73
- Logger::DEBUG
74
- end
43
+ @logger.level = @options.verbose? ? Logger::DEBUG : Logger::INFO
75
44
  end
76
45
  end
77
46
  end
@@ -0,0 +1,49 @@
1
+ require "harmoniser/connection"
2
+
3
+ module Harmoniser
4
+ module Connectable
5
+ MUTEX = Mutex.new
6
+
7
+ def connection_opts
8
+ @connection_opts ||= Connection::DEFAULT_CONNECTION_OPTS.merge({logger: Harmoniser.logger})
9
+ end
10
+
11
+ def connection_opts=(opts)
12
+ raise TypeError, "opts must be a Hash object" unless opts.is_a?(Hash)
13
+
14
+ @connection_opts = connection_opts.merge(opts)
15
+ end
16
+
17
+ def connection
18
+ MUTEX.synchronize do
19
+ @connection ||= create_connection
20
+ @connection.start unless @connection.open? || @connection.recovering_from_network_failure?
21
+ @connection
22
+ end
23
+ end
24
+
25
+ def connection?
26
+ !!defined?(@connection)
27
+ end
28
+
29
+ private
30
+
31
+ def create_connection
32
+ at_exit(&method(:at_exit_handler).to_proc)
33
+ Connection.new(connection_opts)
34
+ end
35
+
36
+ def at_exit_handler
37
+ logger = Harmoniser.logger
38
+
39
+ logger.info("Shutting down!")
40
+ if connection? && connection.open?
41
+ stringified_connection = connection.to_s
42
+ logger.info("Connection will be closed: connection = `#{stringified_connection}`")
43
+ connection.close
44
+ logger.info("Connection closed: connection = `#{stringified_connection}`")
45
+ end
46
+ logger.info("Bye!")
47
+ end
48
+ end
49
+ end
@@ -4,18 +4,45 @@ require "bunny"
4
4
  module Harmoniser
5
5
  class Connection
6
6
  extend Forwardable
7
- def_delegators :@bunny, :close, :create_channel, :open?, :start
7
+
8
+ DEFAULT_CONNECTION_OPTS = {
9
+ connection_name: "harmoniser@#{VERSION}",
10
+ connection_timout: 5,
11
+ host: "127.0.0.1",
12
+ password: "guest",
13
+ port: 5672,
14
+ read_timeout: 5,
15
+ recovery_attempt_started: proc {
16
+ stringified_connection = Harmoniser.connection.to_s
17
+ Harmoniser.logger.info("Recovery attempt started: connection = `#{stringified_connection}`")
18
+ },
19
+ recovery_completed: proc {
20
+ stringified_connection = Harmoniser.connection.to_s
21
+ Harmoniser.logger.info("Recovery completed: connection = `#{stringified_connection}`")
22
+ },
23
+ tls_silence_warnings: true,
24
+ username: "guest",
25
+ verify_peer: false,
26
+ vhost: "/",
27
+ write_timeout: 5
28
+ }
29
+
30
+ def_delegators :@bunny, :close, :create_channel, :open?, :recovering_from_network_failure?, :start
8
31
 
9
32
  def initialize(opts)
10
33
  @bunny = Bunny.new(opts)
11
34
  end
12
35
 
13
36
  def to_s
14
- "<#{self.class.name}>: #{user}@#{host}:#{port}, vhost = #{vhost}"
37
+ "<#{self.class.name}>: #{user}@#{host}:#{port}, connection_name = `#{connection_name}`, vhost = `#{vhost}`"
15
38
  end
16
39
 
17
40
  private
18
41
 
42
+ def connection_name
43
+ @bunny.connection_name
44
+ end
45
+
19
46
  def host
20
47
  @bunny.transport.host
21
48
  end
@@ -1,6 +1,6 @@
1
1
  module Harmoniser
2
2
  class Launcher
3
- def initialize(configuration: Harmoniser.configuration, logger: Harmoniser.logger)
3
+ def initialize(configuration:, logger:)
4
4
  @configuration = configuration
5
5
  @logger = logger
6
6
  end
@@ -10,10 +10,6 @@ module Harmoniser
10
10
  start_subscribers
11
11
  end
12
12
 
13
- def stop
14
- stop_subscribers
15
- end
16
-
17
13
  private
18
14
 
19
15
  def boot_app
@@ -33,11 +29,6 @@ module Harmoniser
33
29
  @logger.info("Subscribers registered to consume messages from queues: klasses = `#{klasses}`")
34
30
  end
35
31
 
36
- def stop_subscribers
37
- @logger.info("Connection will be closed: connection = `#{@configuration.connection}`")
38
- @configuration.connection.close
39
- end
40
-
41
32
  private
42
33
 
43
34
  def load_rails
@@ -0,0 +1,10 @@
1
+ require "logger"
2
+ require "harmoniser/version"
3
+
4
+ module Harmoniser
5
+ module Loggable
6
+ def logger
7
+ @logger ||= Logger.new($stdout, progname: "harmoniser@#{VERSION}")
8
+ end
9
+ end
10
+ end
@@ -5,8 +5,6 @@ module Harmoniser
5
5
  module Publisher
6
6
  class MissingExchangeDefinition < StandardError; end
7
7
  include Channelable
8
- MUTEX = Mutex.new
9
- private_constant :MUTEX
10
8
 
11
9
  module ClassMethods
12
10
  def harmoniser_publisher(exchange_name:)
@@ -20,7 +18,7 @@ module Harmoniser
20
18
  def publish(payload, opts = {})
21
19
  raise_missing_exchange_definition unless @harmoniser_exchange_definition
22
20
 
23
- MUTEX.synchronize do
21
+ const_get(:HARMONISER_PUBLISHER_MUTEX).synchronize do
24
22
  harmoniser_exchange.publish(payload, opts)
25
23
  end
26
24
  Harmoniser.logger.debug { "Message published: payload = `#{payload}`, opts = `#{opts}`" }
@@ -31,10 +29,8 @@ module Harmoniser
31
29
  private
32
30
 
33
31
  def harmoniser_exchange
34
- return @harmoniser_exchange if @harmoniser_exchange
35
-
36
32
  @harmoniser_exchange ||= Bunny::Exchange.new(
37
- Publisher.harmoniser_channel,
33
+ Publisher.create_channel,
38
34
  @harmoniser_exchange_definition.type,
39
35
  @harmoniser_exchange_definition.name,
40
36
  @harmoniser_exchange_definition.opts
@@ -48,6 +44,7 @@ module Harmoniser
48
44
 
49
45
  class << self
50
46
  def included(base)
47
+ base.const_set(:HARMONISER_PUBLISHER_MUTEX, Mutex.new)
51
48
  base.extend(ClassMethods)
52
49
  end
53
50
  end
@@ -7,8 +7,6 @@ module Harmoniser
7
7
  class MissingConsumerDefinition < StandardError; end
8
8
  include Channelable
9
9
  include Includable
10
- MUTEX = Mutex.new
11
- private_constant :MUTEX
12
10
 
13
11
  module ClassMethods
14
12
  def harmoniser_subscriber(queue_name:, consumer_tag: nil, no_ack: true, exclusive: false, arguments: {})
@@ -22,7 +20,7 @@ module Harmoniser
22
20
  end
23
21
 
24
22
  def harmoniser_subscriber_start
25
- MUTEX.synchronize do
23
+ const_get(:HARMONISER_SUBSCRIBER_MUTEX).synchronize do
26
24
  @harmoniser_consumer ||= create_consumer
27
25
  end
28
26
  end
@@ -32,10 +30,11 @@ module Harmoniser
32
30
  def create_consumer
33
31
  raise_missing_consumer_definition unless @harmoniser_consumer_definition
34
32
 
33
+ channel = Subscriber.create_channel
35
34
  consumer = Bunny::Consumer.new(
36
- Subscriber.harmoniser_channel,
35
+ channel,
37
36
  @harmoniser_consumer_definition.queue_name,
38
- @harmoniser_consumer_definition.consumer_tag || Subscriber.harmoniser_channel.generate_consumer_tag,
37
+ @harmoniser_consumer_definition.consumer_tag || channel.generate_consumer_tag,
39
38
  @harmoniser_consumer_definition.no_ack,
40
39
  @harmoniser_consumer_definition.exclusive,
41
40
  @harmoniser_consumer_definition.arguments
@@ -77,6 +76,7 @@ module Harmoniser
77
76
 
78
77
  class << self
79
78
  def included(base)
79
+ base.const_set(:HARMONISER_SUBSCRIBER_MUTEX, Mutex.new)
80
80
  base.extend(ClassMethods)
81
81
  harmoniser_register_included(base)
82
82
  end
@@ -1,3 +1,3 @@
1
1
  module Harmoniser
2
- VERSION = "0.4.0"
2
+ VERSION = "0.6.0"
3
3
  end
data/lib/harmoniser.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  require "harmoniser/version"
2
2
  require "harmoniser/configurable"
3
+ require "harmoniser/loggable"
3
4
  require "harmoniser/publisher"
4
5
  require "harmoniser/subscriber"
5
6
 
6
7
  module Harmoniser
7
8
  extend Configurable
9
+ extend Loggable
8
10
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: harmoniser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jose Lloret
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-07 00:00:00.000000000 Z
11
+ date: 2023-12-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bunny
@@ -89,10 +89,12 @@ files:
89
89
  - lib/harmoniser/cli.rb
90
90
  - lib/harmoniser/configurable.rb
91
91
  - lib/harmoniser/configuration.rb
92
+ - lib/harmoniser/connectable.rb
92
93
  - lib/harmoniser/connection.rb
93
94
  - lib/harmoniser/definition.rb
94
95
  - lib/harmoniser/includable.rb
95
96
  - lib/harmoniser/launcher.rb
97
+ - lib/harmoniser/loggable.rb
96
98
  - lib/harmoniser/options.rb
97
99
  - lib/harmoniser/parser.rb
98
100
  - lib/harmoniser/publisher.rb