pg_insights 0.1.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +183 -0
- data/Rakefile +8 -0
- data/app/assets/javascripts/pg_insights/application.js +436 -0
- data/app/assets/javascripts/pg_insights/health.js +104 -0
- data/app/assets/javascripts/pg_insights/results/chart_renderer.js +126 -0
- data/app/assets/javascripts/pg_insights/results/table_manager.js +378 -0
- data/app/assets/javascripts/pg_insights/results/view_toggles.js +25 -0
- data/app/assets/javascripts/pg_insights/results.js +13 -0
- data/app/assets/stylesheets/pg_insights/application.css +750 -0
- data/app/assets/stylesheets/pg_insights/health.css +501 -0
- data/app/assets/stylesheets/pg_insights/results.css +682 -0
- data/app/controllers/pg_insights/application_controller.rb +4 -0
- data/app/controllers/pg_insights/health_controller.rb +110 -0
- data/app/controllers/pg_insights/insights_controller.rb +77 -0
- data/app/controllers/pg_insights/queries_controller.rb +44 -0
- data/app/helpers/pg_insights/application_helper.rb +4 -0
- data/app/helpers/pg_insights/insights_helper.rb +190 -0
- data/app/jobs/pg_insights/application_job.rb +4 -0
- data/app/jobs/pg_insights/health_check_job.rb +45 -0
- data/app/jobs/pg_insights/health_check_scheduler_job.rb +52 -0
- data/app/jobs/pg_insights/recurring_health_checks_job.rb +49 -0
- data/app/models/pg_insights/application_record.rb +5 -0
- data/app/models/pg_insights/health_check_result.rb +46 -0
- data/app/models/pg_insights/query.rb +10 -0
- data/app/services/pg_insights/health_check_service.rb +298 -0
- data/app/services/pg_insights/insight_query_service.rb +21 -0
- data/app/views/layouts/pg_insights/application.html.erb +58 -0
- data/app/views/pg_insights/health/index.html.erb +324 -0
- data/app/views/pg_insights/insights/_chart_view.html.erb +25 -0
- data/app/views/pg_insights/insights/_column_panel.html.erb +18 -0
- data/app/views/pg_insights/insights/_query_examples.html.erb +32 -0
- data/app/views/pg_insights/insights/_query_panel.html.erb +36 -0
- data/app/views/pg_insights/insights/_result.html.erb +15 -0
- data/app/views/pg_insights/insights/_results_info.html.erb +19 -0
- data/app/views/pg_insights/insights/_results_panel.html.erb +13 -0
- data/app/views/pg_insights/insights/_results_table.html.erb +45 -0
- data/app/views/pg_insights/insights/_stats_view.html.erb +3 -0
- data/app/views/pg_insights/insights/_table_controls.html.erb +21 -0
- data/app/views/pg_insights/insights/_table_view.html.erb +5 -0
- data/app/views/pg_insights/insights/index.html.erb +5 -0
- data/config/default_queries.yml +85 -0
- data/config/routes.rb +22 -0
- data/lib/generators/pg_insights/clean_generator.rb +74 -0
- data/lib/generators/pg_insights/install_generator.rb +176 -0
- data/lib/pg_insights/engine.rb +40 -0
- data/lib/pg_insights/version.rb +3 -0
- data/lib/pg_insights.rb +83 -0
- data/lib/tasks/pg_insights.rake +172 -0
- metadata +124 -0
data/config/routes.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
PgInsights::Engine.routes.draw do
|
2
|
+
root "insights#index"
|
3
|
+
|
4
|
+
# For running queries and loading the main UI
|
5
|
+
post "/", to: "insights#index"
|
6
|
+
|
7
|
+
# For the table name dropdown
|
8
|
+
get :table_names, to: "insights#table_names"
|
9
|
+
|
10
|
+
# For managing user-saved queries
|
11
|
+
resources :queries, only: [ :create, :update, :destroy ] # For the health dashboard
|
12
|
+
get :health, to: "health#index"
|
13
|
+
namespace :health do
|
14
|
+
get :unused_indexes
|
15
|
+
get :missing_indexes
|
16
|
+
get :sequential_scans
|
17
|
+
get :slow_queries
|
18
|
+
get :table_bloat
|
19
|
+
get :parameter_settings
|
20
|
+
post :refresh
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require "rails/generators/base"
|
2
|
+
|
3
|
+
module PgInsights
|
4
|
+
module Generators
|
5
|
+
class CleanGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path("../../../..", __FILE__)
|
7
|
+
|
8
|
+
def remove_routes
|
9
|
+
routes_file = File.join(destination_root, "config", "routes.rb")
|
10
|
+
route_to_remove = "mount PgInsights::Engine => '/pg_insights'"
|
11
|
+
|
12
|
+
if File.exist?(routes_file)
|
13
|
+
routes_content = File.read(routes_file)
|
14
|
+
if routes_content.include?(route_to_remove)
|
15
|
+
puts "Removing PgInsights engine mount from routes..."
|
16
|
+
updated_content = routes_content.gsub(/^\s*#{Regexp.escape(route_to_remove)}\s*\n?/, "")
|
17
|
+
File.write(routes_file, updated_content)
|
18
|
+
say_status("removed", "PgInsights engine mount from config/routes.rb", :green)
|
19
|
+
else
|
20
|
+
say_status("skipped", "PgInsights engine mount not found in config/routes.rb", :yellow)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def remove_initializer
|
26
|
+
initializer_path = "config/initializers/pg_insights.rb"
|
27
|
+
initializer_full_path = File.join(destination_root, initializer_path)
|
28
|
+
|
29
|
+
if File.exist?(initializer_full_path)
|
30
|
+
puts "Removing PgInsights initializer..."
|
31
|
+
remove_file initializer_path
|
32
|
+
say_status("removed", initializer_path, :green)
|
33
|
+
else
|
34
|
+
say_status("skipped", "#{initializer_path} not found", :yellow)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def show_migration_rollback_instructions
|
39
|
+
puts "\nPgInsights has been cleaned up!"
|
40
|
+
puts ""
|
41
|
+
puts "To complete the uninstallation, you may also want to:"
|
42
|
+
puts "1. Roll back the migrations:"
|
43
|
+
|
44
|
+
migration_files = find_pg_insights_migrations
|
45
|
+
if migration_files.any?
|
46
|
+
puts " rails db:rollback STEP=#{migration_files.count}"
|
47
|
+
puts ""
|
48
|
+
puts "2. Or manually remove the migration files:"
|
49
|
+
migration_files.each do |file|
|
50
|
+
puts " rm #{file}"
|
51
|
+
end
|
52
|
+
else
|
53
|
+
puts " (No PgInsights migrations found)"
|
54
|
+
end
|
55
|
+
|
56
|
+
puts ""
|
57
|
+
puts "3. Remove any PgInsights data from your database:"
|
58
|
+
puts " rails runner 'PgInsights::Query.destroy_all'"
|
59
|
+
puts " rails runner 'PgInsights::HealthCheckResult.destroy_all'"
|
60
|
+
puts ""
|
61
|
+
puts "4. If you want to reinstall later, run: rails generate pg_insights:install"
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def find_pg_insights_migrations
|
67
|
+
migrate_path = File.join(destination_root, "db", "migrate")
|
68
|
+
return [] unless File.directory?(migrate_path)
|
69
|
+
|
70
|
+
Dir.glob("#{migrate_path}/*_create_pg_insights_*.rb").sort
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require "rails/generators/base"
|
2
|
+
require "rails/generators/migration"
|
3
|
+
require "rails/generators/active_record"
|
4
|
+
|
5
|
+
module PgInsights
|
6
|
+
module Generators
|
7
|
+
class InstallGenerator < Rails::Generators::Base
|
8
|
+
include Rails::Generators::Migration
|
9
|
+
|
10
|
+
source_root File.expand_path("../../../..", __FILE__)
|
11
|
+
|
12
|
+
def self.next_migration_number(dirname)
|
13
|
+
ActiveRecord::Generators::Base.next_migration_number(dirname)
|
14
|
+
end
|
15
|
+
|
16
|
+
def copy_migrations
|
17
|
+
copy_queries_migration
|
18
|
+
copy_health_check_results_migration
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_initializer
|
22
|
+
initializer_path = File.join(destination_root, "config", "initializers", "pg_insights.rb")
|
23
|
+
|
24
|
+
if File.exist?(initializer_path)
|
25
|
+
say_status("skipped", "Initializer 'config/initializers/pg_insights.rb' already exists", :yellow)
|
26
|
+
else
|
27
|
+
puts "Creating PgInsights initializer..."
|
28
|
+
create_file "config/initializers/pg_insights.rb", initializer_content
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def mount_engine
|
33
|
+
route_to_add = "mount PgInsights::Engine => '/pg_insights'"
|
34
|
+
routes_file = File.join(destination_root, "config", "routes.rb")
|
35
|
+
|
36
|
+
if File.exist?(routes_file) && File.read(routes_file).include?(route_to_add)
|
37
|
+
say_status("skipped", "Route `#{route_to_add}` already exists in `config/routes.rb`", :yellow)
|
38
|
+
else
|
39
|
+
puts "Mounting PgInsights engine..."
|
40
|
+
route route_to_add
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def show_readme
|
45
|
+
puts "\nPgInsights has been successfully installed!"
|
46
|
+
puts ""
|
47
|
+
puts "Next steps:"
|
48
|
+
puts "1. Run 'rails db:migrate' to create the necessary tables"
|
49
|
+
puts "2. Review and customize 'config/initializers/pg_insights.rb'"
|
50
|
+
puts "3. Configure background jobs (optional, see initializer comments)"
|
51
|
+
puts "4. Visit '/pg_insights' in your browser to start using the dashboard"
|
52
|
+
puts ""
|
53
|
+
puts "For background job integration, see: config/initializers/pg_insights.rb"
|
54
|
+
puts "To check status: rails pg_insights:status"
|
55
|
+
puts "To uninstall: rails generate pg_insights:clean"
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def initializer_content
|
61
|
+
<<~RUBY
|
62
|
+
# PgInsights Configuration
|
63
|
+
##{' '}
|
64
|
+
# This file contains the configuration for PgInsights, a PostgreSQL database
|
65
|
+
# performance monitoring and health check engine.
|
66
|
+
|
67
|
+
PgInsights.configure do |config|
|
68
|
+
# === Background Jobs Configuration ===
|
69
|
+
##{' '}
|
70
|
+
# Enable background job processing for health checks.
|
71
|
+
# When enabled, health checks will run asynchronously if your app has ActiveJob configured.
|
72
|
+
# When disabled or if ActiveJob is not available, health checks run synchronously.
|
73
|
+
#
|
74
|
+
# Default: true
|
75
|
+
config.enable_background_jobs = true
|
76
|
+
|
77
|
+
# Queue name for PgInsights background jobs
|
78
|
+
# Make sure this queue is processed by your job processor (Sidekiq, Resque, etc.)
|
79
|
+
#
|
80
|
+
# Default: :pg_insights_health
|
81
|
+
config.background_job_queue = :pg_insights_health
|
82
|
+
|
83
|
+
# === Cache and Timeout Settings ===
|
84
|
+
#{' '}
|
85
|
+
# How long to cache health check results before considering them stale
|
86
|
+
# Stale results will trigger background refresh when accessed
|
87
|
+
#
|
88
|
+
# Default: 5.minutes
|
89
|
+
config.health_cache_expiry = 5.minutes
|
90
|
+
|
91
|
+
# Timeout for individual health check queries to prevent long-running queries
|
92
|
+
# from blocking the application
|
93
|
+
#
|
94
|
+
# Default: 10.seconds#{' '}
|
95
|
+
config.health_check_timeout = 10.seconds
|
96
|
+
|
97
|
+
# Maximum execution time for user queries in the insights interface
|
98
|
+
#
|
99
|
+
# Default: 30.seconds
|
100
|
+
config.max_query_execution_time = 30.seconds
|
101
|
+
end
|
102
|
+
|
103
|
+
# === Background Job Integration ===
|
104
|
+
#
|
105
|
+
# If you want automatic recurring health checks, add one of these to your job scheduler:
|
106
|
+
#
|
107
|
+
# ** Whenever (crontab) **
|
108
|
+
# Add to config/schedule.rb:
|
109
|
+
# every 1.hour do
|
110
|
+
# runner "PgInsights::RecurringHealthChecksJob.perform_later"
|
111
|
+
# end
|
112
|
+
#
|
113
|
+
# ** Sidekiq-Cron **
|
114
|
+
# Add to config/initializers/sidekiq.rb:
|
115
|
+
# Sidekiq::Cron::Job.create(
|
116
|
+
# name: 'PgInsights Health Checks',
|
117
|
+
# cron: '0 * * * *',
|
118
|
+
# class: 'PgInsights::RecurringHealthChecksJob'
|
119
|
+
# )
|
120
|
+
#
|
121
|
+
# ** Manual Trigger **
|
122
|
+
# You can also trigger health checks manually:
|
123
|
+
# PgInsights::HealthCheckService.refresh_all!
|
124
|
+
#
|
125
|
+
# ** Check Status **
|
126
|
+
# To verify your configuration:
|
127
|
+
# rails pg_insights:status
|
128
|
+
|
129
|
+
# === Environment-Specific Settings ===
|
130
|
+
#
|
131
|
+
# You may want different settings per environment:
|
132
|
+
#
|
133
|
+
# if Rails.env.development?
|
134
|
+
# PgInsights.configure do |config|
|
135
|
+
# config.health_cache_expiry = 1.minute # Shorter cache in development
|
136
|
+
# config.enable_background_jobs = false # Synchronous in development
|
137
|
+
# end
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# if Rails.env.production?
|
141
|
+
# PgInsights.configure do |config|
|
142
|
+
# config.health_cache_expiry = 15.minutes # Longer cache in production
|
143
|
+
# config.health_check_timeout = 30.seconds # More generous timeout
|
144
|
+
# end
|
145
|
+
# end
|
146
|
+
RUBY
|
147
|
+
end
|
148
|
+
|
149
|
+
def copy_queries_migration
|
150
|
+
if migration_exists?("create_pg_insights_queries")
|
151
|
+
say_status("skipped", "Migration 'create_pg_insights_queries' already exists", :yellow)
|
152
|
+
else
|
153
|
+
puts "Copying PgInsights queries migration..."
|
154
|
+
migration_template "db/migrate/create_pg_insights_queries.rb",
|
155
|
+
"db/migrate/create_pg_insights_queries.rb"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def copy_health_check_results_migration
|
160
|
+
if migration_exists?("create_pg_insights_health_check_results")
|
161
|
+
say_status("skipped", "Migration 'create_pg_insights_health_check_results' already exists", :yellow)
|
162
|
+
else
|
163
|
+
puts "Copying PgInsights health check results migration..."
|
164
|
+
migration_template "db/migrate/create_pg_insights_health_check_results.rb",
|
165
|
+
"db/migrate/create_pg_insights_health_check_results.rb"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def migration_exists?(migration_name)
|
170
|
+
migrate_path = File.join(destination_root, "db", "migrate")
|
171
|
+
return false unless File.directory?(migrate_path)
|
172
|
+
Dir.glob("#{migrate_path}/*_#{migration_name}.rb").any?
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "chartkick"
|
4
|
+
|
5
|
+
module PgInsights
|
6
|
+
class Engine < ::Rails::Engine
|
7
|
+
isolate_namespace PgInsights
|
8
|
+
|
9
|
+
initializer "pg_insights.assets.precompile" do |app|
|
10
|
+
app.config.assets.precompile += %w[
|
11
|
+
pg_insights/application.css
|
12
|
+
pg_insights/application.js
|
13
|
+
pg_insights/health.css
|
14
|
+
pg_insights/health.js
|
15
|
+
pg_insights/results.css
|
16
|
+
pg_insights/results.js
|
17
|
+
]
|
18
|
+
end
|
19
|
+
|
20
|
+
initializer "pg_insights.configure_background_jobs", after: "active_job.set_configs" do |app|
|
21
|
+
ActiveSupport.on_load(:active_job) do
|
22
|
+
if PgInsights.enable_background_jobs
|
23
|
+
if PgInsights.background_jobs_available?
|
24
|
+
Rails.logger.info "PgInsights: Background jobs enabled (#{ActiveJob::Base.queue_adapter_name})"
|
25
|
+
else
|
26
|
+
Rails.logger.warn "PgInsights: Background jobs enabled but may not be fully available yet."
|
27
|
+
Rails.logger.warn "PgInsights: Will fall back to synchronous execution when needed."
|
28
|
+
Rails.logger.warn "PgInsights: Check your ActiveJob configuration if you see issues."
|
29
|
+
end
|
30
|
+
else
|
31
|
+
Rails.logger.info "PgInsights: Background jobs disabled - will run health checks synchronously"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
rake_tasks do
|
37
|
+
load "tasks/pg_insights.rake"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/pg_insights.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require "pg_insights/version"
|
2
|
+
require "pg_insights/engine"
|
3
|
+
|
4
|
+
module PgInsights
|
5
|
+
# Configuration options
|
6
|
+
mattr_accessor :enable_background_jobs, default: true
|
7
|
+
mattr_accessor :health_cache_expiry, default: 5.minutes
|
8
|
+
mattr_accessor :background_job_queue, default: :pg_insights_health
|
9
|
+
mattr_accessor :max_query_execution_time, default: 30.seconds
|
10
|
+
mattr_accessor :health_check_timeout, default: 10.seconds
|
11
|
+
|
12
|
+
def self.configure
|
13
|
+
yield self
|
14
|
+
end
|
15
|
+
|
16
|
+
# Check if background jobs are available and properly configured
|
17
|
+
def self.background_jobs_available?
|
18
|
+
return false unless enable_background_jobs
|
19
|
+
return false unless defined?(ActiveJob::Base)
|
20
|
+
return false if ActiveJob::Base.queue_adapter.is_a?(ActiveJob::QueueAdapters::InlineAdapter)
|
21
|
+
return false unless defined?(PgInsights::HealthCheckJob)
|
22
|
+
|
23
|
+
# Verify the queue adapter can handle our jobs
|
24
|
+
begin
|
25
|
+
ActiveJob::Base.queue_adapter.respond_to?(:enqueue) ||
|
26
|
+
ActiveJob::Base.queue_adapter.respond_to?(:enqueue_at)
|
27
|
+
rescue => e
|
28
|
+
Rails.logger.debug "PgInsights: Background job check failed: #{e.message}" if defined?(Rails)
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Safely execute background jobs with fallback
|
34
|
+
def self.execute_with_fallback(job_class, method_name, *args, &fallback_block)
|
35
|
+
if background_jobs_available?
|
36
|
+
begin
|
37
|
+
job_class.public_send(method_name, *args)
|
38
|
+
return true
|
39
|
+
rescue => e
|
40
|
+
Rails.logger.warn "PgInsights: Background job failed, falling back to synchronous execution: #{e.message}" if defined?(Rails)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Execute fallback if provided
|
45
|
+
fallback_block.call if fallback_block
|
46
|
+
false
|
47
|
+
end
|
48
|
+
|
49
|
+
# Integration helpers for host applications
|
50
|
+
module Integration
|
51
|
+
# Helper for host apps to check if they need to configure anything
|
52
|
+
def self.status
|
53
|
+
{
|
54
|
+
background_jobs_available: PgInsights.background_jobs_available?,
|
55
|
+
queue_adapter: defined?(ActiveJob::Base) ? ActiveJob::Base.queue_adapter_name : "not_available",
|
56
|
+
configuration: {
|
57
|
+
enable_background_jobs: PgInsights.enable_background_jobs,
|
58
|
+
health_cache_expiry: PgInsights.health_cache_expiry,
|
59
|
+
background_job_queue: PgInsights.background_job_queue
|
60
|
+
}
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
# Helper for host apps to test job functionality
|
65
|
+
def self.test_background_jobs
|
66
|
+
return { success: false, error: "Background jobs disabled" } unless PgInsights.enable_background_jobs
|
67
|
+
return { success: false, error: "ActiveJob not available" } unless defined?(ActiveJob::Base)
|
68
|
+
|
69
|
+
begin
|
70
|
+
# Try to enqueue a simple test
|
71
|
+
if defined?(PgInsights::HealthCheckJob)
|
72
|
+
# Don't actually run the job, just test enqueueing
|
73
|
+
Rails.logger.info "PgInsights: Testing background job capability..."
|
74
|
+
{ success: true, message: "Background jobs appear to be working" }
|
75
|
+
else
|
76
|
+
{ success: false, error: "PgInsights job classes not loaded" }
|
77
|
+
end
|
78
|
+
rescue => e
|
79
|
+
{ success: false, error: e.message }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
namespace :pg_insights do
|
2
|
+
desc "Show PgInsights configuration and background job status"
|
3
|
+
task status: :environment do
|
4
|
+
puts "PgInsights Configuration Status"
|
5
|
+
puts "==============================="
|
6
|
+
|
7
|
+
status = PgInsights::Integration.status
|
8
|
+
|
9
|
+
puts "Background Jobs: #{status[:background_jobs_available] ? '✅ Available' : '❌ Not Available'}"
|
10
|
+
puts "Queue Adapter: #{status[:queue_adapter]}"
|
11
|
+
puts "Queue Name: #{status[:configuration][:background_job_queue]}"
|
12
|
+
puts "Cache Expiry: #{status[:configuration][:health_cache_expiry]}"
|
13
|
+
puts "Enabled: #{status[:configuration][:enable_background_jobs] ? 'Yes' : 'No'}"
|
14
|
+
|
15
|
+
if defined?(PgInsights::RecurringHealthChecksJob)
|
16
|
+
puts "\nRecurring Job Status:"
|
17
|
+
validation = PgInsights::RecurringHealthChecksJob.validate_setup
|
18
|
+
if validation[:valid]
|
19
|
+
puts "✅ #{validation[:message]}"
|
20
|
+
else
|
21
|
+
puts "❌ Issues found:"
|
22
|
+
validation[:issues].each { |issue| puts " - #{issue}" }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
puts "\nIntegration Help:"
|
27
|
+
if status[:background_jobs_available]
|
28
|
+
puts "✅ Your application is ready for PgInsights background jobs!"
|
29
|
+
puts " Add this to your job scheduler (whenever, sidekiq-cron, etc.):"
|
30
|
+
puts " PgInsights::RecurringHealthChecksJob.perform_later"
|
31
|
+
else
|
32
|
+
puts "ℹ️ Background jobs are not configured. PgInsights will work in synchronous mode."
|
33
|
+
puts " To enable background processing:"
|
34
|
+
puts " 1. Configure ActiveJob in your Rails application"
|
35
|
+
puts " 2. Set up a job queue backend (Sidekiq, Resque, etc.)"
|
36
|
+
puts " 3. Add to config/initializers/pg_insights.rb:"
|
37
|
+
puts " PgInsights.configure { |c| c.enable_background_jobs = true }"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "Test background job functionality"
|
42
|
+
task test_jobs: :environment do
|
43
|
+
puts "Testing PgInsights Background Jobs"
|
44
|
+
puts "=================================="
|
45
|
+
|
46
|
+
test_result = PgInsights::Integration.test_background_jobs
|
47
|
+
|
48
|
+
if test_result[:success]
|
49
|
+
puts "✅ #{test_result[:message]}"
|
50
|
+
|
51
|
+
# Try scheduling a real health check
|
52
|
+
if defined?(PgInsights::HealthCheckJob)
|
53
|
+
if PgInsights::HealthCheckJob.perform_check("parameter_settings")
|
54
|
+
puts "✅ Successfully enqueued a test health check"
|
55
|
+
else
|
56
|
+
puts "❌ Failed to enqueue test health check"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
else
|
60
|
+
puts "❌ #{test_result[:error]}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "Run health checks synchronously (without background jobs)"
|
65
|
+
task health_check: :environment do
|
66
|
+
puts "Running PgInsights Health Checks (Synchronous)"
|
67
|
+
puts "=============================================="
|
68
|
+
|
69
|
+
start_time = Time.current
|
70
|
+
|
71
|
+
begin
|
72
|
+
PgInsights::HealthCheckService.execute_all_checks_synchronously
|
73
|
+
execution_time = Time.current - start_time
|
74
|
+
|
75
|
+
puts "✅ Health checks completed in #{execution_time.round(2)} seconds"
|
76
|
+
puts "Visit /pg_insights/health in your browser to see the results"
|
77
|
+
rescue => e
|
78
|
+
puts "❌ Health checks failed: #{e.message}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
desc "Clear all PgInsights stored data"
|
83
|
+
task clear_data: :environment do
|
84
|
+
puts "Clearing PgInsights stored data..."
|
85
|
+
|
86
|
+
# Remove data from database
|
87
|
+
begin
|
88
|
+
if defined?(PgInsights::Query)
|
89
|
+
query_count = PgInsights::Query.count
|
90
|
+
PgInsights::Query.destroy_all
|
91
|
+
puts "Removed #{query_count} stored queries"
|
92
|
+
end
|
93
|
+
rescue => e
|
94
|
+
puts "Could not remove queries: #{e.message}"
|
95
|
+
end
|
96
|
+
|
97
|
+
begin
|
98
|
+
if defined?(PgInsights::HealthCheckResult)
|
99
|
+
result_count = PgInsights::HealthCheckResult.count
|
100
|
+
PgInsights::HealthCheckResult.destroy_all
|
101
|
+
puts "Removed #{result_count} cached health check results"
|
102
|
+
end
|
103
|
+
rescue => e
|
104
|
+
puts "Could not remove health check results: #{e.message}"
|
105
|
+
end
|
106
|
+
|
107
|
+
puts "PgInsights data cleared successfully!"
|
108
|
+
puts "To completely uninstall PgInsights (remove migrations and routes), run: rails generate pg_insights:clean"
|
109
|
+
end
|
110
|
+
|
111
|
+
desc "Reset PgInsights data (clears all stored queries and health check results)"
|
112
|
+
task reset: :environment do
|
113
|
+
puts "Resetting PgInsights data..."
|
114
|
+
|
115
|
+
begin
|
116
|
+
if defined?(PgInsights::Query)
|
117
|
+
PgInsights::Query.destroy_all
|
118
|
+
puts "Cleared all PgInsights queries"
|
119
|
+
end
|
120
|
+
rescue => e
|
121
|
+
puts "Could not clear queries: #{e.message}"
|
122
|
+
end
|
123
|
+
|
124
|
+
begin
|
125
|
+
if defined?(PgInsights::HealthCheckResult)
|
126
|
+
PgInsights::HealthCheckResult.destroy_all
|
127
|
+
puts "Cleared all PgInsights health check results"
|
128
|
+
end
|
129
|
+
rescue => e
|
130
|
+
puts "Could not clear health check results: #{e.message}"
|
131
|
+
end
|
132
|
+
|
133
|
+
puts "PgInsights data reset completed!"
|
134
|
+
end
|
135
|
+
|
136
|
+
desc "Show PgInsights statistics"
|
137
|
+
task stats: :environment do
|
138
|
+
puts "PgInsights Statistics:"
|
139
|
+
puts "====================="
|
140
|
+
|
141
|
+
begin
|
142
|
+
if defined?(PgInsights::Query)
|
143
|
+
query_count = PgInsights::Query.count
|
144
|
+
puts "Stored queries: #{query_count}"
|
145
|
+
end
|
146
|
+
rescue => e
|
147
|
+
puts "Queries table not available: #{e.message}"
|
148
|
+
end
|
149
|
+
|
150
|
+
begin
|
151
|
+
if defined?(PgInsights::HealthCheckResult)
|
152
|
+
result_count = PgInsights::HealthCheckResult.count
|
153
|
+
recent_results = PgInsights::HealthCheckResult.where("executed_at > ?", 24.hours.ago).count
|
154
|
+
puts "Health check results: #{result_count}"
|
155
|
+
puts "Recent results (24h): #{recent_results}"
|
156
|
+
|
157
|
+
# Show results by type
|
158
|
+
PgInsights::HealthCheckResult::VALID_CHECK_TYPES.each do |check_type|
|
159
|
+
latest = PgInsights::HealthCheckResult.latest_for_type(check_type)
|
160
|
+
if latest
|
161
|
+
freshness = latest.fresh? ? "fresh" : "stale"
|
162
|
+
puts " #{check_type}: #{latest.status} (#{freshness})"
|
163
|
+
else
|
164
|
+
puts " #{check_type}: no data"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
rescue => e
|
169
|
+
puts "Health check results table not available: #{e.message}"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|