flu-rails 8.0.2 → 8.0.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -0
- data/README.md +3 -3
- data/lib/flu-rails/action_controller_extender.rb +3 -1
- data/lib/flu-rails/dummy/in_memory_event_publisher.rb +8 -1
- data/lib/flu-rails/event_factory.rb +7 -6
- data/lib/flu-rails/event_publisher.rb +31 -8
- data/lib/flu-rails/railtie.rb +7 -4
- data/lib/flu-rails/version.rb +1 -1
- data/lib/flu-rails.rb +4 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5fadf301a677ec0ec47d67f9eb8159aac7dfab535c268030331ce4d54c391e58
|
|
4
|
+
data.tar.gz: 90c8b9dc6c71fa9f01630b1e183114132ec1d63735cdc2cb62c5974750f3ff49
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2a8f50d7eb2796ce8408f3a1ca36b68d55020d8858134fc136cef7be6fcb7978c316e99298a2d394ef0f0555602c1a955b3ff497b0a72e9b1f49ddf23ec4e1b8
|
|
7
|
+
data.tar.gz: dbc5b57979a4ebe601b8df0c26822c7dfa127c44f7292b97b654aff0363d04266552a60c2bda0d0ea00b2865421e47677d4f66592bf8c9e36bf6820f1ea290e8
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,39 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
### [8.0.4] - 2026-08-01
|
|
9
|
+
|
|
10
|
+
**Security**
|
|
11
|
+
|
|
12
|
+
* Honour the host application's `config.filter_parameters` when publishing a `request` event.
|
|
13
|
+
|
|
14
|
+
**Fixed**
|
|
15
|
+
|
|
16
|
+
* Stop opening two RabbitMQ connections on every boot. The railtie called `Flu.start
|
|
17
|
+
* Close the publisher that `Flu.init` replaces.
|
|
18
|
+
|
|
19
|
+
**Added**
|
|
20
|
+
|
|
21
|
+
* `EventPublisher#disconnect` and `EventPublisher#connected?`.
|
|
22
|
+
|
|
23
|
+
**Changed**
|
|
24
|
+
|
|
25
|
+
* `ignored_request_params` and `default_ignored_request_params` are now matched as strings.
|
|
26
|
+
* A published `request` event may now carry `"[FILTERED]"` in place of a param value.
|
|
27
|
+
* `EventPublisher#connect` is now idempotent: calling it on a connected publisher does nothing
|
|
28
|
+
instead of opening a second connection.
|
|
29
|
+
|
|
30
|
+
**Tests**
|
|
31
|
+
|
|
32
|
+
* Cover the connection lifecycle against a real broker: redundant `connect` calls, `disconnect`,
|
|
33
|
+
`connected?`, and reconnection after a disconnect — including an example asserting that no session
|
|
34
|
+
is left open behind the publisher.
|
|
35
|
+
* Cover `Flu.init` disconnecting the publisher it replaces.
|
|
36
|
+
|
|
37
|
+
### [8.0.3] - 2026-08-01
|
|
38
|
+
|
|
39
|
+
* Use `uuid_v7` as Event ID (requires Ruby 3.3)
|
|
40
|
+
|
|
8
41
|
### [8.0.2] - 2026-08-01
|
|
9
42
|
|
|
10
43
|
**Fixed**
|
data/README.md
CHANGED
|
@@ -164,7 +164,7 @@ All options have a default value. However, all of them can be changed in your in
|
|
|
164
164
|
| `rabbitmq_exchange_durable` | `true` | Boolean | Optional | Make the RabbitMQ's exchange durable or not. From RabbitMQ's [documentation](https://www.rabbitmq.com/tutorials/amqp-concepts.html#exchanges): _"Durable exchanges survive broker restart whereas transient exchanges do not (they have to be redeclared when broker comes back online)."_ | `false` |
|
|
165
165
|
| `auto_connect_to_exchange` | `true`| Boolean | Optional | Thanks to `Railties`, `flu-rails` starts automatically when the Rails app boots. However, this can be useful to not connect RabbitMQ at start up. To do so, set `auto_connect_to_exchange` to `false`. | `false` |
|
|
166
166
|
| `default_ignored_model_changes` | `[:password, :password_confirmation, :created_at, :updated_at]` | Boolean | Optional | By default, all these attributes will be ignored from model changes when creating an event. For instance, this means that timestamp fields (`created_at` and `updated_at`) are not monitored when they change. | `[]` |
|
|
167
|
-
| `default_ignored_request_params` | `[:password, :password_confirmation, :controller, :action]` | Boolean | Optional | By default, all these parameters will be ignored from controller request's `params` when creating an event. | `false` |
|
|
167
|
+
| `default_ignored_request_params` | `[:password, :password_confirmation, :controller, :action]` | Boolean | Optional | By default, all these parameters will be ignored from controller request's `params` when creating an event. Independently of this option, any parameter your Rails application already masks through `config.filter_parameters` (passwords, tokens,...) is replaced with `"[FILTERED]"` in the event too, including inside nested params. | `false` |
|
|
168
168
|
| `application_name` | `Rails.application.class.module_parent_name`, resolved on startup | String | Required | Is used as `emitter` for each event created by `flu-rails`, if not overriden by the `track_met`. | `my_app` |
|
|
169
169
|
| `bunny_options` | `{}` | Hash of symbols | Optional | Additional options to add when connecting the RabbitMQ broker. This overrides the existing options with the same name. | `{ verify_peer: true }` |
|
|
170
170
|
|
|
@@ -304,8 +304,8 @@ scoped RubyGems credential.
|
|
|
304
304
|
3. Tag the commit and push the tag:
|
|
305
305
|
|
|
306
306
|
```
|
|
307
|
-
$ git tag -a v8.0.
|
|
308
|
-
$ git push origin v8.0.
|
|
307
|
+
$ git tag -a v8.0.4 -m "Version 8.0.4"
|
|
308
|
+
$ git push origin v8.0.4
|
|
309
309
|
```
|
|
310
310
|
|
|
311
311
|
The workflow then checks that the tag matches `Flu::VERSION`, runs the tests, builds the gem
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
require "active_support/core_ext/string/inflections"
|
|
2
2
|
require "active_support/core_ext/time/zones"
|
|
3
|
+
require "random/formatter"
|
|
4
|
+
require "securerandom"
|
|
3
5
|
|
|
4
6
|
module Flu
|
|
5
7
|
class ActionControllerExtender
|
|
@@ -28,7 +30,7 @@ module Flu
|
|
|
28
30
|
# landed on ActionController::Base itself, leaking onto every controller of the host
|
|
29
31
|
# application. Here 'self' is the class calling 'track_requests', which is where they belong.
|
|
30
32
|
define_method(:flu_define_request_id) do
|
|
31
|
-
request_id = SecureRandom.uuid
|
|
33
|
+
request_id = Random.respond_to?(:uuid_v7) ? Random.uuid_v7 : SecureRandom.uuid
|
|
32
34
|
@flu_request_id = request_id
|
|
33
35
|
Flu::CoreExt.flu_tracker_request_id = request_id
|
|
34
36
|
end
|
|
@@ -11,7 +11,7 @@ module Flu
|
|
|
11
11
|
@configuration = configuration
|
|
12
12
|
@emitter = configuration.application_name
|
|
13
13
|
@default_ignored_model_changes = configuration.default_ignored_model_changes.map(&:to_s)
|
|
14
|
-
@default_ignored_request_params = configuration.default_ignored_request_params
|
|
14
|
+
@default_ignored_request_params = configuration.default_ignored_request_params.map(&:to_s)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def build_request_event(data)
|
|
@@ -50,7 +50,8 @@ module Flu
|
|
|
50
50
|
final_emitter = overriden_emitter.blank? ? original_emitter : overriden_emitter
|
|
51
51
|
# 'overriden_emitter' selects the emitter of the event, it is not part of what is tracked:
|
|
52
52
|
# it is dropped from the payload instead of being published as an 'overridenEmitter' key.
|
|
53
|
-
|
|
53
|
+
uuid = Random.respond_to?(:uuid_v7) ? Random.uuid_v7 : SecureRandom.uuid
|
|
54
|
+
Event.new(uuid, final_emitter, kind, name, deep_camelize(data.except(:overriden_emitter)))
|
|
54
55
|
end
|
|
55
56
|
|
|
56
57
|
def create_data_from_entity_changes(action_name, entity, request_id, request_entity_metadata, changes, user_metadata_lambda, association_columns, ignored_model_changes, flu_overriden_emitter_lambda)
|
|
@@ -76,15 +77,15 @@ module Flu
|
|
|
76
77
|
response_code: response.status,
|
|
77
78
|
user_agent: request.user_agent,
|
|
78
79
|
duration: Time.zone.now - request_start_time,
|
|
79
|
-
params: extract_params(
|
|
80
|
+
params: extract_params(request, ignored_request_params)
|
|
80
81
|
}
|
|
81
82
|
end
|
|
82
83
|
|
|
83
84
|
private
|
|
84
85
|
|
|
85
|
-
def extract_params(
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
def extract_params(request, ignored_request_params)
|
|
87
|
+
excluded_params = ignored_request_params.map(&:to_s) + @default_ignored_request_params
|
|
88
|
+
request.filtered_parameters.except(*excluded_params)
|
|
88
89
|
end
|
|
89
90
|
|
|
90
91
|
def deep_camelize(value)
|
|
@@ -17,18 +17,41 @@ module Flu
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def connect
|
|
20
|
-
connected
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
unless connected?
|
|
21
|
+
connected = false
|
|
22
|
+
while !connected
|
|
23
|
+
begin
|
|
24
|
+
connect_to_exchange
|
|
25
|
+
connected = true
|
|
26
|
+
rescue Bunny::TCPConnectionFailedForAllHosts
|
|
27
|
+
@logger.warn("RabbitMQ connection failed, try again in 1 second.")
|
|
28
|
+
sleep 1
|
|
29
|
+
end
|
|
28
30
|
end
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
33
|
|
|
34
|
+
def connected?
|
|
35
|
+
if @connection.nil? || @exchange.nil?
|
|
36
|
+
false
|
|
37
|
+
else
|
|
38
|
+
@connection.open?
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Closing the connection closes the channel opened on it, and stops the heartbeat and recovery
|
|
43
|
+
# threads Bunny runs alongside it.
|
|
44
|
+
# The guard is on the connection alone, not on 'connected?': a connection that was opened before
|
|
45
|
+
# the exchange could be declared still has to be closed.
|
|
46
|
+
def disconnect
|
|
47
|
+
if !@connection.nil? && @connection.open?
|
|
48
|
+
@connection.close
|
|
49
|
+
end
|
|
50
|
+
@connection = nil
|
|
51
|
+
@channel = nil
|
|
52
|
+
@exchange = nil
|
|
53
|
+
end
|
|
54
|
+
|
|
32
55
|
private
|
|
33
56
|
|
|
34
57
|
def connect_to_exchange
|
data/lib/flu-rails/railtie.rb
CHANGED
|
@@ -2,13 +2,16 @@ module Flu
|
|
|
2
2
|
class Railtie < Rails::Railtie
|
|
3
3
|
railtie_name :flu
|
|
4
4
|
|
|
5
|
+
# 'to_prepare' runs before eager loading, so that 'track_entity_changes' and 'track_requests'
|
|
6
|
+
# exist by the time the application's models and controllers are loaded. It runs again on every
|
|
7
|
+
# code reload, where 'Flu.init' builds a new publisher which has to be connected too.
|
|
8
|
+
#
|
|
9
|
+
# There is deliberately no 'after_initialize' hook here: it also runs at boot, right after this
|
|
10
|
+
# one, and the 'Flu.start' it used to make opened a second connection that replaced — and
|
|
11
|
+
# therefore leaked — the connection opened above.
|
|
5
12
|
config.to_prepare do
|
|
6
13
|
Flu.init
|
|
7
14
|
Flu.start
|
|
8
15
|
end
|
|
9
|
-
|
|
10
|
-
config.after_initialize do
|
|
11
|
-
Flu.start
|
|
12
|
-
end
|
|
13
16
|
end
|
|
14
17
|
end
|
data/lib/flu-rails/version.rb
CHANGED
data/lib/flu-rails.rb
CHANGED
|
@@ -38,6 +38,10 @@ module Flu
|
|
|
38
38
|
raise "configuration.application_name must not be nil" if @configuration.application_name.nil?
|
|
39
39
|
@logger = @configuration.logger
|
|
40
40
|
@event_factory = Flu::EventFactory.new(@configuration)
|
|
41
|
+
# The railtie re-runs 'init' on every code reload. The publisher being replaced owns an open
|
|
42
|
+
# connection, its channel and Bunny's heartbeat thread: dropping the reference to it without
|
|
43
|
+
# closing it leaks all three for the lifetime of the process.
|
|
44
|
+
@event_publisher&.disconnect
|
|
41
45
|
@event_publisher = create_event_publisher(@configuration)
|
|
42
46
|
extend_models_and_controllers
|
|
43
47
|
end
|