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 +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +2 -12
- data/docs/cli.md +1 -1
- data/lib/harmoniser/cli.rb +3 -5
- data/lib/harmoniser/configurable.rb +1 -1
- data/lib/harmoniser/configuration.rb +5 -36
- data/lib/harmoniser/connectable.rb +49 -0
- data/lib/harmoniser/connection.rb +29 -2
- data/lib/harmoniser/launcher.rb +1 -10
- data/lib/harmoniser/loggable.rb +10 -0
- data/lib/harmoniser/publisher.rb +3 -6
- data/lib/harmoniser/subscriber.rb +5 -5
- data/lib/harmoniser/version.rb +1 -1
- data/lib/harmoniser.rb +2 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4410b741fa891c42db5f51dc48889768859a9a84a3eed3676fc35f0aaeb8cca1
|
4
|
+
data.tar.gz: c6af823a40e9b007f93a347e84ad44aee26dea0e10464fc608c116db7185ec19
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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#
|
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#
|
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
|
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.
|
data/lib/harmoniser/cli.rb
CHANGED
@@ -46,19 +46,17 @@ module Harmoniser
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def run
|
49
|
-
|
50
|
-
|
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
|
|
@@ -1,33 +1,20 @@
|
|
1
1
|
require "forwardable"
|
2
|
-
require "
|
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
|
-
|
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 =
|
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 =
|
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
|
-
|
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 =
|
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
|
data/lib/harmoniser/launcher.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Harmoniser
|
2
2
|
class Launcher
|
3
|
-
def initialize(configuration
|
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
|
data/lib/harmoniser/publisher.rb
CHANGED
@@ -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
|
-
|
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.
|
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
|
-
|
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
|
-
|
35
|
+
channel,
|
37
36
|
@harmoniser_consumer_definition.queue_name,
|
38
|
-
@harmoniser_consumer_definition.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
|
data/lib/harmoniser/version.rb
CHANGED
data/lib/harmoniser.rb
CHANGED
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
|
+
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-
|
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
|