discord_rda 0.1.3 → 0.2.0

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.
@@ -54,6 +54,7 @@ module DiscordRDA
54
54
  # Class-level API client
55
55
  class << self
56
56
  attr_accessor :api
57
+ attr_accessor :supervisor
57
58
  end
58
59
 
59
60
  # Get interaction type as symbol
@@ -439,6 +440,17 @@ module DiscordRDA
439
440
  self.class.api.delete("/webhooks/#{application_id}/#{token}/messages/#{message_id}")
440
441
  end
441
442
 
443
+ def run_isolated(ruby_code:, timeout_seconds: 15, memory_limit_mb: nil, env: {})
444
+ raise 'Execution supervisor not configured' unless self.class.supervisor
445
+
446
+ self.class.supervisor.run_isolated(
447
+ ruby_code: ruby_code,
448
+ timeout_seconds: timeout_seconds,
449
+ memory_limit_mb: memory_limit_mb,
450
+ env: env
451
+ )
452
+ end
453
+
442
454
  # Show premium required response
443
455
  # @return [void]
444
456
  def premium_required
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'active_record'
5
+
6
+ module DiscordRDA
7
+ class ActiveRecordSystem
8
+ attr_reader :logger
9
+
10
+ def initialize(logger: nil)
11
+ @logger = logger
12
+ @connected = false
13
+ end
14
+
15
+ def connect(database_url: nil, **config)
16
+ require 'active_record'
17
+
18
+ connection_config = config.dup
19
+ connection_config[:url] = database_url if database_url
20
+ connection_config[:url] ||= ENV['DATABASE_URL']
21
+ raise ArgumentError, 'database_url or DATABASE_URL is required' unless connection_config[:url]
22
+
23
+ ::ActiveRecord::Base.establish_connection(connection_config)
24
+ ::DiscordRDA::Record.connection
25
+ @connected = true
26
+ logger&.info('ActiveRecord connected', adapter: ::ActiveRecord::Base.connection_db_config.adapter)
27
+ self
28
+ end
29
+
30
+ def connected?
31
+ @connected && ::ActiveRecord::Base.connected?
32
+ rescue StandardError
33
+ false
34
+ end
35
+
36
+ def disconnect
37
+ return unless defined?(::ActiveRecord::Base)
38
+
39
+ ::ActiveRecord::Base.connection_pool.disconnect!
40
+ @connected = false
41
+ end
42
+
43
+ def migration_context(paths = default_migration_paths)
44
+ require 'active_record'
45
+
46
+ paths.each { |path| FileUtils.mkdir_p(path) }
47
+ ::ActiveRecord::MigrationContext.new(paths, ::ActiveRecord::SchemaMigration)
48
+ end
49
+
50
+ def migrate(paths = default_migration_paths)
51
+ migration_context(paths).migrate
52
+ end
53
+
54
+ def rollback(paths = default_migration_paths, steps: 1)
55
+ migration_context(paths).rollback(steps)
56
+ end
57
+
58
+ def default_migration_paths
59
+ ['db/migrate']
60
+ end
61
+ end
62
+
63
+ class Record < ::ActiveRecord::Base
64
+ self.abstract_class = true
65
+ end
66
+
67
+ module ActiveRecordMigration
68
+ def self.[](version = 7.1)
69
+ Class.new(::ActiveRecord::Migration[version])
70
+ end
71
+ end
72
+ end
@@ -182,6 +182,45 @@ module DiscordRDA
182
182
  }
183
183
  end
184
184
 
185
+ def prometheus_export
186
+ data = summary
187
+
188
+ [
189
+ '# HELP discord_rda_uptime_seconds Process uptime in seconds',
190
+ '# TYPE discord_rda_uptime_seconds gauge',
191
+ "discord_rda_uptime_seconds #{data[:uptime]}",
192
+ '# HELP discord_rda_gateway_events_per_minute Gateway events per minute',
193
+ '# TYPE discord_rda_gateway_events_per_minute gauge',
194
+ "discord_rda_gateway_events_per_minute #{data[:gateway][:events_per_minute]}",
195
+ '# HELP discord_rda_rest_requests_per_minute REST requests per minute',
196
+ '# TYPE discord_rda_rest_requests_per_minute gauge',
197
+ "discord_rda_rest_requests_per_minute #{data[:rest][:requests_per_minute]}",
198
+ '# HELP discord_rda_cache_hit_rate Cache hit rate percentage',
199
+ '# TYPE discord_rda_cache_hit_rate gauge',
200
+ "discord_rda_cache_hit_rate #{data[:cache][:hit_rate]}",
201
+ '# HELP discord_rda_shards_total_guilds Guilds across shards',
202
+ '# TYPE discord_rda_shards_total_guilds gauge',
203
+ "discord_rda_shards_total_guilds #{data[:shards][:total_guilds]}"
204
+ ].join("\n") + "\n"
205
+ end
206
+
207
+ def grafana_dashboard(title: 'DiscordRDA Overview')
208
+ dashboard = {
209
+ title: title,
210
+ schemaVersion: 39,
211
+ version: 1,
212
+ editable: true,
213
+ panels: [
214
+ metric_panel(id: 1, title: 'Gateway Events / Min', expr: 'discord_rda_gateway_events_per_minute'),
215
+ metric_panel(id: 2, title: 'REST Requests / Min', expr: 'discord_rda_rest_requests_per_minute'),
216
+ metric_panel(id: 3, title: 'Cache Hit Rate', expr: 'discord_rda_cache_hit_rate'),
217
+ metric_panel(id: 4, title: 'Guilds', expr: 'discord_rda_shards_total_guilds')
218
+ ]
219
+ }
220
+
221
+ Oj.dump(dashboard, mode: :compat)
222
+ end
223
+
185
224
  # Run comprehensive health checks
186
225
  # @return [Hash] Health check results
187
226
  def run_health_checks
@@ -311,6 +350,17 @@ module DiscordRDA
311
350
  }
312
351
  end
313
352
 
353
+ def metric_panel(id:, title:, expr:)
354
+ {
355
+ id: id,
356
+ type: 'stat',
357
+ title: title,
358
+ datasource: { type: 'prometheus', uid: '${DS_PROMETHEUS}' },
359
+ targets: [{ expr: expr, refId: "A#{id}" }],
360
+ gridPos: { h: 8, w: 12, x: ((id - 1) % 2) * 12, y: ((id - 1) / 2) * 8 }
361
+ }
362
+ end
363
+
314
364
  # Get memory usage
315
365
  # @return [Hash] Memory usage info
316
366
  def memory_usage
@@ -323,10 +373,22 @@ module DiscordRDA
323
373
  { error: 'Unable to retrieve' }
324
374
  end
325
375
 
326
- # Get CPU usage (simplified)
376
+ # Get process CPU usage
327
377
  # @return [Hash] CPU usage info
328
378
  def cpu_usage
329
- # This is a simplified implementation
379
+ process_times = Process.times
380
+ elapsed = uptime_seconds
381
+ total_cpu_seconds = process_times.utime + process_times.stime
382
+ cpu_percent = elapsed.positive? ? ((total_cpu_seconds / elapsed) * 100.0).round(2) : 0.0
383
+
384
+ {
385
+ available: true,
386
+ user_seconds: process_times.utime.round(4),
387
+ system_seconds: process_times.stime.round(4),
388
+ total_seconds: total_cpu_seconds.round(4),
389
+ utilization_percent: cpu_percent
390
+ }
391
+ rescue StandardError
330
392
  { available: false }
331
393
  end
332
394
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DiscordRDA
4
- VERSION = '0.1.3'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/discord_rda.rb CHANGED
@@ -7,7 +7,12 @@
7
7
  require_relative 'discord_rda/version'
8
8
  require_relative 'discord_rda/core/async_runtime'
9
9
  require_relative 'discord_rda/core/configuration'
10
+ require_relative 'discord_rda/core/execution_supervisor'
10
11
  require_relative 'discord_rda/core/logger'
12
+ require_relative 'discord_rda/core/restart_manager'
13
+ require_relative 'discord_rda/core/tracer'
14
+ require_relative 'discord_rda/core/error_tracker'
15
+ require_relative 'discord_rda/core/secrets'
11
16
  require_relative 'discord_rda/core/snowflake'
12
17
  require_relative 'discord_rda/entity/base'
13
18
  require_relative 'discord_rda/entity/factory'
@@ -25,6 +30,7 @@ require_relative 'discord_rda/entity/emoji'
25
30
  require_relative 'discord_rda/entity/attachment'
26
31
  require_relative 'discord_rda/entity/embed'
27
32
  require_relative 'discord_rda/entity/support'
33
+ require_relative 'discord_rda/persistence/active_record'
28
34
  require_relative 'discord_rda/connection/rate_limiter'
29
35
  require_relative 'discord_rda/connection/invalid_bucket'
30
36
  require_relative 'discord_rda/connection/request_queue'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: discord_rda
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Júlia Klee
@@ -51,6 +51,48 @@ dependencies:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
53
  version: '0.30'
54
+ - !ruby/object:Gem::Dependency
55
+ name: activerecord
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '7.1'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '7.1'
68
+ - !ruby/object:Gem::Dependency
69
+ name: base64
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: lru_redux
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '1.1'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '1.1'
54
96
  - !ruby/object:Gem::Dependency
55
97
  name: oj
56
98
  requirement: !ruby/object:Gem::Requirement
@@ -149,6 +191,20 @@ dependencies:
149
191
  - - "~>"
150
192
  - !ruby/object:Gem::Version
151
193
  version: '1.17'
194
+ - !ruby/object:Gem::Dependency
195
+ name: erb
196
+ requirement: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ type: :development
202
+ prerelease: false
203
+ version_requirements: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - ">="
206
+ - !ruby/object:Gem::Version
207
+ version: '0'
152
208
  - !ruby/object:Gem::Dependency
153
209
  name: rake
154
210
  requirement: !ruby/object:Gem::Requirement
@@ -247,8 +303,13 @@ files:
247
303
  - lib/discord_rda/connection/shard_manager.rb
248
304
  - lib/discord_rda/core/async_runtime.rb
249
305
  - lib/discord_rda/core/configuration.rb
306
+ - lib/discord_rda/core/error_tracker.rb
307
+ - lib/discord_rda/core/execution_supervisor.rb
250
308
  - lib/discord_rda/core/logger.rb
309
+ - lib/discord_rda/core/restart_manager.rb
310
+ - lib/discord_rda/core/secrets.rb
251
311
  - lib/discord_rda/core/snowflake.rb
312
+ - lib/discord_rda/core/tracer.rb
252
313
  - lib/discord_rda/entity/attachment.rb
253
314
  - lib/discord_rda/entity/base.rb
254
315
  - lib/discord_rda/entity/channel.rb
@@ -274,6 +335,7 @@ files:
274
335
  - lib/discord_rda/interactions/command_system.rb
275
336
  - lib/discord_rda/interactions/components.rb
276
337
  - lib/discord_rda/interactions/interaction.rb
338
+ - lib/discord_rda/persistence/active_record.rb
277
339
  - lib/discord_rda/plugin/analytics_plugin.rb
278
340
  - lib/discord_rda/plugin/base.rb
279
341
  - lib/discord_rda/plugin/registry.rb
@@ -289,7 +351,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
289
351
  requirements:
290
352
  - - ">="
291
353
  - !ruby/object:Gem::Version
292
- version: 3.0.0
354
+ version: 3.4.0
293
355
  required_rubygems_version: !ruby/object:Gem::Requirement
294
356
  requirements:
295
357
  - - ">="