activerabbit-ai 0.5.0 โ 0.5.2
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 +9 -0
- data/README.md +1 -1
- data/TESTING_GUIDE.md +5 -5
- data/examples/rails_integration.rb +3 -3
- data/examples/standalone_usage.rb +4 -4
- data/lib/active_rabbit/client/configuration.rb +21 -5
- data/lib/active_rabbit/client/dedupe.rb +10 -1
- data/lib/active_rabbit/client/http_client.rb +50 -19
- data/lib/active_rabbit/client/railtie.rb +31 -0
- data/lib/active_rabbit/client/version.rb +1 -1
- data/lib/active_rabbit/client.rb +11 -9
- data/script/test_production_readiness.rb +4 -4
- metadata +2 -3
- data/lib/active_rabbit-client.gemspec +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d349dcd013eaa9c787d218d695e4e45d779b4c236fc908b84edbda42ac0471b8
|
|
4
|
+
data.tar.gz: 92c559e16a816706558028588f8869212b05e41fb10507d5fc8c40902ca95a62
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f26d6cd48e6ba74b87cbdfb5adae1c89dfba13c623c0acfc7418c7061bf3559c66a48061a136a166bdb69a5e06cf1a5d6ee5067c35e20932dd4b98966ad03bcf
|
|
7
|
+
data.tar.gz: daf29ace4927b42c216a8c88df12291f783b599d32a4443e19426854f336c00fb571ae63d2f6003d05707409b150768cc0ed1c42fd12d348e7bb80689a96aabb
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.5.2] - 2025-12-22
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **Batch sending resilience**: `HttpClient#post_batch` is now nil-safe and supports both queued items and raw payloads (prevents `undefined method [] for nil` during flush).
|
|
9
|
+
- **Dedupe resilience**: Deduplication key building is now safe when `context` is nil/non-hash.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- **Default API URL**: Default `api_url` aligned to `https://app.activerabbit.ai` (dashboard + API host).
|
|
13
|
+
|
|
5
14
|
## [0.5.0] - 2025-12-12
|
|
6
15
|
|
|
7
16
|
### Changed
|
data/README.md
CHANGED
|
@@ -38,7 +38,7 @@ Or install it yourself as:
|
|
|
38
38
|
ActiveRabbit::Client.configure do |config|
|
|
39
39
|
config.api_key = ENV['ACTIVERABBIT_API_KEY']
|
|
40
40
|
config.project_id = ENV['ACTIVERABBIT_PROJECT_ID']
|
|
41
|
-
config.api_url = ENV.fetch('ACTIVERABBIT_API_URL', 'https://
|
|
41
|
+
config.api_url = ENV.fetch('ACTIVERABBIT_API_URL', 'https://app.activerabbit.ai')
|
|
42
42
|
config.environment = Rails.env
|
|
43
43
|
end
|
|
44
44
|
```
|
data/TESTING_GUIDE.md
CHANGED
|
@@ -69,7 +69,7 @@ end
|
|
|
69
69
|
RSpec.describe ActiveRabbit::Client::Configuration do
|
|
70
70
|
describe "environment variable loading" do
|
|
71
71
|
it "loads API key from environment" do
|
|
72
|
-
allow(ENV).to receive(:[]).with("
|
|
72
|
+
allow(ENV).to receive(:[]).with("ACTIVERABBIT_API_KEY").and_return("test-key")
|
|
73
73
|
config = described_class.new
|
|
74
74
|
expect(config.api_key).to eq("test-key")
|
|
75
75
|
end
|
|
@@ -486,8 +486,8 @@ puts "๐งช Testing ActiveRabbit Integration..."
|
|
|
486
486
|
# Test 1: Configuration
|
|
487
487
|
puts "\n1. Testing Configuration..."
|
|
488
488
|
ActiveRabbit::Client.configure do |config|
|
|
489
|
-
config.api_key = ENV['
|
|
490
|
-
config.project_id = ENV['
|
|
489
|
+
config.api_key = ENV['ACTIVERABBIT_API_KEY'] || 'test-key'
|
|
490
|
+
config.project_id = ENV['ACTIVERABBIT_PROJECT_ID'] || 'test-project'
|
|
491
491
|
config.environment = 'test'
|
|
492
492
|
end
|
|
493
493
|
|
|
@@ -578,8 +578,8 @@ jobs:
|
|
|
578
578
|
bundle exec rspec
|
|
579
579
|
ruby script/test_activerabbit.rb
|
|
580
580
|
env:
|
|
581
|
-
|
|
582
|
-
|
|
581
|
+
ACTIVERABBIT_API_KEY: ${{ secrets.ACTIVERABBIT_API_KEY }}
|
|
582
|
+
ACTIVERABBIT_PROJECT_ID: ${{ secrets.ACTIVERABBIT_PROJECT_ID }}
|
|
583
583
|
```
|
|
584
584
|
|
|
585
585
|
This comprehensive testing approach ensures your Rails application and ActiveRabbit gem integration is thoroughly tested before production deployment, covering functionality, performance, and resilience scenarios.
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
# config/initializers/active_rabbit.rb
|
|
6
6
|
ActiveRabbit::Client.configure do |config|
|
|
7
7
|
# Required configuration
|
|
8
|
-
config.api_key = ENV['
|
|
9
|
-
config.project_id = ENV['
|
|
8
|
+
config.api_key = ENV['ACTIVERABBIT_API_KEY']
|
|
9
|
+
config.project_id = ENV['ACTIVERABBIT_PROJECT_ID']
|
|
10
10
|
config.environment = Rails.env
|
|
11
11
|
|
|
12
12
|
# Optional configuration
|
|
13
|
-
config.api_url = ENV.fetch('
|
|
13
|
+
config.api_url = ENV.fetch('ACTIVERABBIT_API_URL', 'https://api.activerabbit.com')
|
|
14
14
|
config.release = ENV['HEROKU_SLUG_COMMIT'] || `git rev-parse HEAD`.chomp
|
|
15
15
|
|
|
16
16
|
# Performance settings
|
|
@@ -140,8 +140,8 @@ class BackgroundWorker
|
|
|
140
140
|
def initialize
|
|
141
141
|
# Configure ActiveRabbit for background processes
|
|
142
142
|
ActiveRabbit::Client.configure do |config|
|
|
143
|
-
config.api_key = ENV['
|
|
144
|
-
config.project_id = ENV['
|
|
143
|
+
config.api_key = ENV['ACTIVERABBIT_API_KEY']
|
|
144
|
+
config.project_id = ENV['ACTIVERABBIT_PROJECT_ID']
|
|
145
145
|
config.environment = ENV.fetch('ENVIRONMENT', 'development')
|
|
146
146
|
config.server_name = "worker-#{Socket.gethostname}"
|
|
147
147
|
end
|
|
@@ -249,8 +249,8 @@ namespace :data do
|
|
|
249
249
|
desc "Migrate user data"
|
|
250
250
|
task migrate_users: :environment do
|
|
251
251
|
ActiveRabbit::Client.configure do |config|
|
|
252
|
-
config.api_key = ENV['
|
|
253
|
-
config.project_id = ENV['
|
|
252
|
+
config.api_key = ENV['ACTIVERABBIT_API_KEY']
|
|
253
|
+
config.project_id = ENV['ACTIVERABBIT_PROJECT_ID']
|
|
254
254
|
config.environment = 'migration'
|
|
255
255
|
end
|
|
256
256
|
|
|
@@ -16,13 +16,14 @@ module ActiveRabbit
|
|
|
16
16
|
attr_accessor :before_send_event, :before_send_exception
|
|
17
17
|
attr_accessor :dedupe_window # Time window in seconds for error deduplication (0 = disabled)
|
|
18
18
|
attr_accessor :revision
|
|
19
|
+
attr_accessor :auto_release_tracking
|
|
19
20
|
attr_accessor :disable_console_logs
|
|
20
21
|
|
|
21
22
|
def initialize
|
|
22
|
-
@api_url = ENV.fetch("
|
|
23
|
-
@api_key = ENV["
|
|
24
|
-
@project_id = ENV["
|
|
25
|
-
@environment = ENV
|
|
23
|
+
@api_url = ENV.fetch("ACTIVERABBIT_API_URL", "https://app.activerabbit.ai")
|
|
24
|
+
@api_key = ENV["ACTIVERABBIT_API_KEY"]
|
|
25
|
+
@project_id = ENV["ACTIVERABBIT_PROJECT_ID"]
|
|
26
|
+
@environment = ENV["ACTIVERABBIT_ENVIRONMENT"] || detect_environment
|
|
26
27
|
|
|
27
28
|
# HTTP settings
|
|
28
29
|
@timeout = 30
|
|
@@ -68,9 +69,10 @@ module ActiveRabbit
|
|
|
68
69
|
@dedupe_window = 300 # 5 minutes by default
|
|
69
70
|
|
|
70
71
|
# Metadata
|
|
71
|
-
@release = detect_release
|
|
72
72
|
@server_name = detect_server_name
|
|
73
73
|
@logger = detect_logger
|
|
74
|
+
@auto_release_tracking = default_auto_release_tracking
|
|
75
|
+
@revision = detect_release
|
|
74
76
|
|
|
75
77
|
# Callbacks
|
|
76
78
|
@before_send_event = nil
|
|
@@ -138,6 +140,20 @@ module ActiveRabbit
|
|
|
138
140
|
ENV["RACK_ENV"] || ENV["RAILS_ENV"] || "development"
|
|
139
141
|
end
|
|
140
142
|
|
|
143
|
+
def default_auto_release_tracking
|
|
144
|
+
# Allow explicit override via env var
|
|
145
|
+
env_value = ENV["ACTIVERABBIT_AUTO_RELEASE_TRACKING"]
|
|
146
|
+
if env_value
|
|
147
|
+
normalized = env_value.to_s.strip.downcase
|
|
148
|
+
return true if %w[1 true yes y on].include?(normalized)
|
|
149
|
+
return false if %w[0 false no n off].include?(normalized)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Default: enabled outside dev/test
|
|
153
|
+
env_name = @environment.to_s
|
|
154
|
+
!%w[development test].include?(env_name)
|
|
155
|
+
end
|
|
156
|
+
|
|
141
157
|
def detect_release
|
|
142
158
|
# Try to detect from common CI/deployment environment variables
|
|
143
159
|
ENV["HEROKU_SLUG_COMMIT"] ||
|
|
@@ -32,7 +32,16 @@ module ActiveRabbit
|
|
|
32
32
|
|
|
33
33
|
def build_key(exception, context)
|
|
34
34
|
top = Array(exception.backtrace).first.to_s
|
|
35
|
-
|
|
35
|
+
ctx = context.is_a?(Hash) ? context : {}
|
|
36
|
+
req = ctx[:request] || ctx["request"]
|
|
37
|
+
req_hash = req.is_a?(Hash) ? req : {}
|
|
38
|
+
|
|
39
|
+
req_id =
|
|
40
|
+
req_hash[:request_id] || req_hash["request_id"] ||
|
|
41
|
+
req_hash[:requestId] || req_hash["requestId"] ||
|
|
42
|
+
ctx[:request_id] || ctx["request_id"] ||
|
|
43
|
+
ctx[:requestId] || ctx["requestId"]
|
|
44
|
+
|
|
36
45
|
[exception.class.name, top, req_id].join("|")
|
|
37
46
|
end
|
|
38
47
|
end
|
|
@@ -77,11 +77,23 @@ module ActiveRabbit
|
|
|
77
77
|
|
|
78
78
|
def post_batch(batch_data)
|
|
79
79
|
# Transform batch data into the format the API expects
|
|
80
|
-
events = batch_data.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
80
|
+
events = Array(batch_data).filter_map do |event|
|
|
81
|
+
next if event.nil?
|
|
82
|
+
|
|
83
|
+
# Support both:
|
|
84
|
+
# - queued items: { method:, path:, data:, timestamp: }
|
|
85
|
+
# - raw payloads: { ...event fields... }
|
|
86
|
+
data =
|
|
87
|
+
(event.is_a?(Hash) ? (event[:data] || event["data"]) : nil) ||
|
|
88
|
+
(event.is_a?(Hash) ? event : nil)
|
|
89
|
+
|
|
90
|
+
next unless data.is_a?(Hash)
|
|
91
|
+
|
|
92
|
+
type =
|
|
93
|
+
data[:event_type] || data["event_type"] ||
|
|
94
|
+
(event.is_a?(Hash) ? (event[:event_type] || event["event_type"] || event[:type] || event["type"]) : nil)
|
|
95
|
+
|
|
96
|
+
{ type: type, data: data }
|
|
85
97
|
end
|
|
86
98
|
|
|
87
99
|
# Send batch to API
|
|
@@ -92,24 +104,29 @@ module ActiveRabbit
|
|
|
92
104
|
response
|
|
93
105
|
end
|
|
94
106
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
req.body = payload.to_json
|
|
107
|
+
# Create (or confirm) a release in the ActiveRabbit API.
|
|
108
|
+
# Treats 409 conflict (already exists) as success to support multiple servers/dynos.
|
|
109
|
+
def post_release(release_data)
|
|
110
|
+
payload = stringify_and_sanitize(release_data)
|
|
111
|
+
uri = build_uri("/api/v1/releases")
|
|
101
112
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
end
|
|
113
|
+
log(:info, "[ActiveRabbit] Pinging release to API...")
|
|
114
|
+
log(:debug, "[ActiveRabbit] Release payload: #{safe_preview(payload)}")
|
|
105
115
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
end
|
|
116
|
+
response = perform_request(uri, :post, payload)
|
|
117
|
+
code = response.code.to_i
|
|
109
118
|
|
|
110
|
-
|
|
119
|
+
if (200..299).include?(code)
|
|
120
|
+
parse_json_or_empty(response.body)
|
|
121
|
+
elsif code == 409
|
|
122
|
+
# Already exists; return parsed body (usually includes id/version)
|
|
123
|
+
parse_json_or_empty(response.body)
|
|
124
|
+
else
|
|
125
|
+
# Use shared error handling (raises)
|
|
126
|
+
handle_response(response)
|
|
127
|
+
end
|
|
111
128
|
rescue => e
|
|
112
|
-
log(:error, "[ActiveRabbit]
|
|
129
|
+
log(:error, "[ActiveRabbit] Release ping failed: #{e.class}: #{e.message}")
|
|
113
130
|
nil
|
|
114
131
|
end
|
|
115
132
|
|
|
@@ -150,6 +167,20 @@ module ActiveRabbit
|
|
|
150
167
|
|
|
151
168
|
private
|
|
152
169
|
|
|
170
|
+
def build_uri(path)
|
|
171
|
+
current_base = URI(configuration.api_url)
|
|
172
|
+
normalized_path = path.start_with?("/") ? path : "/#{path}"
|
|
173
|
+
URI.join(current_base, normalized_path)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def parse_json_or_empty(body)
|
|
177
|
+
return {} if body.nil? || body.empty?
|
|
178
|
+
|
|
179
|
+
JSON.parse(body)
|
|
180
|
+
rescue JSON::ParserError
|
|
181
|
+
body
|
|
182
|
+
end
|
|
183
|
+
|
|
153
184
|
def enqueue_request(method, path, data)
|
|
154
185
|
return if @shutdown
|
|
155
186
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "logger"
|
|
4
|
+
require "concurrent"
|
|
4
5
|
|
|
5
6
|
begin
|
|
6
7
|
require "rails/railtie"
|
|
@@ -39,6 +40,36 @@ module ActiveRabbit
|
|
|
39
40
|
config.release ||= detect_release(app)
|
|
40
41
|
end
|
|
41
42
|
|
|
43
|
+
app.config.after_initialize do
|
|
44
|
+
begin
|
|
45
|
+
cfg = ActiveRabbit::Client.configuration
|
|
46
|
+
next unless cfg
|
|
47
|
+
next unless ActiveRabbit::Client.configured?
|
|
48
|
+
next unless cfg.auto_release_tracking
|
|
49
|
+
|
|
50
|
+
version = cfg.revision || cfg.release
|
|
51
|
+
next if version.nil? || version.to_s.strip.empty?
|
|
52
|
+
|
|
53
|
+
metadata = {
|
|
54
|
+
revision: cfg.revision,
|
|
55
|
+
release: cfg.release,
|
|
56
|
+
server_name: cfg.server_name,
|
|
57
|
+
environment: cfg.environment,
|
|
58
|
+
gem_version: ActiveRabbit::Client::VERSION
|
|
59
|
+
}.compact
|
|
60
|
+
|
|
61
|
+
Concurrent::Future.execute do
|
|
62
|
+
ActiveRabbit::Client.notify_release(
|
|
63
|
+
version: version,
|
|
64
|
+
environment: cfg.environment,
|
|
65
|
+
metadata: metadata
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
rescue => e
|
|
69
|
+
Rails.logger.debug "[ActiveRabbit] auto release tracking failed: #{e.class}: #{e.message}" if defined?(Rails) && Rails.logger
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
42
73
|
# if ActiveRabbit::Client.configuration && !ActiveRabbit::Client.configuration.disable_console_logs
|
|
43
74
|
# if Rails.env.development?
|
|
44
75
|
# ar_puts "\n=== ActiveRabbit Post-Configure ==="
|
data/lib/active_rabbit/client.rb
CHANGED
|
@@ -127,19 +127,21 @@ module ActiveRabbit
|
|
|
127
127
|
track_exception(exception, context: context, user_id: user_id, tags: tags)
|
|
128
128
|
end
|
|
129
129
|
|
|
130
|
-
def
|
|
130
|
+
def notify_release(version: nil, environment: nil, metadata: {})
|
|
131
|
+
return unless configured?
|
|
132
|
+
|
|
133
|
+
cfg = configuration
|
|
134
|
+
version ||= cfg.revision || cfg.release
|
|
135
|
+
environment ||= cfg.environment
|
|
136
|
+
return if version.nil? || version.to_s.strip.empty?
|
|
137
|
+
|
|
131
138
|
payload = {
|
|
132
|
-
revision: Client.configuration.revision,
|
|
133
|
-
environment: Client.configuration.environment,
|
|
134
|
-
project_slug: project_slug,
|
|
135
139
|
version: version,
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
started_at: started_at,
|
|
139
|
-
finished_at: finished_at
|
|
140
|
+
environment: environment,
|
|
141
|
+
metadata: metadata || {}
|
|
140
142
|
}
|
|
141
143
|
|
|
142
|
-
http_client.
|
|
144
|
+
http_client.post_release(payload)
|
|
143
145
|
end
|
|
144
146
|
|
|
145
147
|
def log(level, message)
|
|
@@ -14,9 +14,9 @@ puts "๐ ActiveRabbit Production Readiness Test"
|
|
|
14
14
|
puts "=" * 50
|
|
15
15
|
|
|
16
16
|
# Test configuration
|
|
17
|
-
TEST_API_KEY = ENV['
|
|
18
|
-
TEST_PROJECT_ID = ENV['
|
|
19
|
-
TEST_API_URL = ENV['
|
|
17
|
+
TEST_API_KEY = ENV['ACTIVERABBIT_API_KEY'] || 'test-key-for-validation'
|
|
18
|
+
TEST_PROJECT_ID = ENV['ACTIVERABBIT_PROJECT_ID'] || 'test-project'
|
|
19
|
+
TEST_API_URL = ENV['ACTIVERABBIT_API_URL'] || 'https://api.activerabbit.com'
|
|
20
20
|
|
|
21
21
|
# Load the gem
|
|
22
22
|
begin
|
|
@@ -374,7 +374,7 @@ puts "=" * 50
|
|
|
374
374
|
|
|
375
375
|
if TEST_API_KEY == 'test-key-for-validation'
|
|
376
376
|
puts "โ ๏ธ Note: Tests run with mock configuration"
|
|
377
|
-
puts " Set
|
|
377
|
+
puts " Set ACTIVERABBIT_API_KEY and ACTIVERABBIT_PROJECT_ID"
|
|
378
378
|
puts " environment variables for full integration testing"
|
|
379
379
|
else
|
|
380
380
|
puts "โ
Full integration test completed with real API"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activerabbit-ai
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex Shapalov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-12-
|
|
11
|
+
date: 2025-12-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: concurrent-ruby
|
|
@@ -86,7 +86,6 @@ files:
|
|
|
86
86
|
- examples/rails_app_testing.rb
|
|
87
87
|
- examples/rails_integration.rb
|
|
88
88
|
- examples/standalone_usage.rb
|
|
89
|
-
- lib/active_rabbit-client.gemspec
|
|
90
89
|
- lib/active_rabbit.rb
|
|
91
90
|
- lib/active_rabbit/client.rb
|
|
92
91
|
- lib/active_rabbit/client/action_mailer_patch.rb
|
|
File without changes
|