Skip to content

Commit

Permalink
Fix the connection state query (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
fgarces committed Oct 20, 2020
1 parent 3f2b10a commit dcb8eae
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 123 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# postgres-vacuum-monitor

## v.10.1
- Query bug fix.

## v.10.0
- Add events for connection idle time and state.

Expand Down
2 changes: 1 addition & 1 deletion lib/postgres/vacuum/monitor/query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def connection_state
state, count(*) as connection_count
FROM pg_stat_activity
GROUP BY state
ORDER BY count DESC;
ORDER BY connection_count DESC;
SQL
end

Expand Down
2 changes: 1 addition & 1 deletion lib/postgres/vacuum/monitor/version.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Postgres
module Vacuum
module Monitor
VERSION = '0.10.0'.freeze
VERSION = '0.10.1'.freeze
end
end
end
255 changes: 134 additions & 121 deletions spec/postgres/vacuum/jobs/monitor_job_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,149 +8,162 @@ def self.report_event(name, attributes = {})
let(:job) { Postgres::Vacuum::Jobs::MonitorJob.new }

describe "#perform" do
let(:mock_connection) { double }

before do
allow(mock_connection).to receive(:execute).and_return([])
ActiveRecord::Base.connection_handler.connection_pools.each do |pool|
allow(pool).to receive(:with_connection).and_yield(mock_connection)
context "without a mocked connection" do
before do
allow(Postgres::Vacuum::Monitor.configuration).to receive(:monitor_reporter_class_name).and_return(TestMetricsReporter.name)
end

allow(Postgres::Vacuum::Monitor.configuration).to receive(:monitor_reporter_class_name).and_return(TestMetricsReporter.name)
allow(TestMetricsReporter).to receive(:report_event)
it "executes all the queries" do
expect(job.perform).to eq true
end
end

it "reports long running transaction events" do
allow(mock_connection).to receive(:execute).with(Postgres::Vacuum::Monitor::Query.long_running_transactions).and_return(
[
'xact_start' => 'test_xact_start',
'seconds' => 'test_seconds',
'application_name' => 'test_application_name',
'query' => 'test_query',
'state' => 'test_state',
'wait_event_type' => 'test_wait_event_type',
'backend_xid' => 'test_backend_xid',
'backend_xmin' => 'test_backend_xmin'
]
)

job.perform

expect(TestMetricsReporter).to have_received(:report_event).with(
Postgres::Vacuum::Jobs::MonitorJob::LONG_TRANSACTIONS,
database_name: 'postgres_vacuum_monitor_test',
start_time: 'test_xact_start',
running_time: 'test_seconds',
application_name: 'test_application_name',
most_recent_query: 'test_query',
state: 'test_state',
wait_event_type: 'test_wait_event_type',
transaction_id: 'test_backend_xid',
min_transaction_id: 'test_backend_xmin'
)
end
context "with a mocked connection" do
let(:mock_connection) { double }

it "reports autovacuum lagging events" do
allow(mock_connection).to receive(:execute).with(Postgres::Vacuum::Monitor::Query.tables_eligible_vacuuming).and_return(
[
'relation' => 'test_relation',
'table_size' => 512,
'dead_tuples' => 3,
'autovacuum_vacuum_tuples' => 1
]
)

job.perform

expect(TestMetricsReporter).to have_received(:report_event).with(
Postgres::Vacuum::Jobs::MonitorJob::AUTOVACUUM_LAGGING_EVENT,
database_name: 'postgres_vacuum_monitor_test',
table: 'test_relation',
table_size: 512,
dead_tuples: 3,
tuples_over_limit: 2
)
end
before do
allow(mock_connection).to receive(:execute).and_return([])
ActiveRecord::Base.connection_handler.connection_pools.each do |pool|
allow(pool).to receive(:with_connection).and_yield(mock_connection)
end

it "reports blocked queries" do
allow(mock_connection).to receive(:execute).with(Postgres::Vacuum::Monitor::Query.blocked_queries).and_return(
[
'blocked_pid' => 2,
'blocked_application' => 'foo',
'blocked_statement' => 'SELECT 1 FROM products',
'blocking_pid' => 3,
'blocking_application' => 'bar',
'current_statement_in_blocking_process' => 'SELECT 2 FROM products'
]
)

job.perform

expect(TestMetricsReporter).to have_received(:report_event).with(
Postgres::Vacuum::Jobs::MonitorJob::BLOCKED_QUERIES,
database_name: 'postgres_vacuum_monitor_test',
blocked_application: 'foo',
blocked_pid: 2,
blocked_statement: 'SELECT 1 FROM products',
blocking_pid: 3,
blocking_application: 'bar',
current_statement_in_blocking_process: 'SELECT 2 FROM products'
)
end
allow(Postgres::Vacuum::Monitor.configuration).to receive(:monitor_reporter_class_name).and_return(TestMetricsReporter.name)
allow(TestMetricsReporter).to receive(:report_event)
end

it "reports connection state" do
allow(mock_connection).to receive(:execute).with(Postgres::Vacuum::Monitor::Query.connection_state).and_return(
['connection_count' => 4, 'state' => 'idle']
)
it "reports long running transaction events" do
allow(mock_connection).to receive(:execute).with(Postgres::Vacuum::Monitor::Query.long_running_transactions).and_return(
[
'xact_start' => 'test_xact_start',
'seconds' => 'test_seconds',
'application_name' => 'test_application_name',
'query' => 'test_query',
'state' => 'test_state',
'wait_event_type' => 'test_wait_event_type',
'backend_xid' => 'test_backend_xid',
'backend_xmin' => 'test_backend_xmin'
]
)

job.perform

expect(TestMetricsReporter).to have_received(:report_event).with(
Postgres::Vacuum::Jobs::MonitorJob::LONG_TRANSACTIONS,
database_name: 'postgres_vacuum_monitor_test',
start_time: 'test_xact_start',
running_time: 'test_seconds',
application_name: 'test_application_name',
most_recent_query: 'test_query',
state: 'test_state',
wait_event_type: 'test_wait_event_type',
transaction_id: 'test_backend_xid',
min_transaction_id: 'test_backend_xmin'
)
end

job.perform
it "reports autovacuum lagging events" do
allow(mock_connection).to receive(:execute).with(Postgres::Vacuum::Monitor::Query.tables_eligible_vacuuming).and_return(
[
'relation' => 'test_relation',
'table_size' => 512,
'dead_tuples' => 3,
'autovacuum_vacuum_tuples' => 1
]
)

job.perform

expect(TestMetricsReporter).to have_received(:report_event).with(
Postgres::Vacuum::Jobs::MonitorJob::AUTOVACUUM_LAGGING_EVENT,
database_name: 'postgres_vacuum_monitor_test',
table: 'test_relation',
table_size: 512,
dead_tuples: 3,
tuples_over_limit: 2
)
end

expect(TestMetricsReporter).to have_received(:report_event).with(
Postgres::Vacuum::Jobs::MonitorJob::CONNECTION_STATE,
database_name: 'postgres_vacuum_monitor_test',
connection_count: 4,
state: 'idle'
)
end
it "reports blocked queries" do
allow(mock_connection).to receive(:execute).with(Postgres::Vacuum::Monitor::Query.blocked_queries).and_return(
[
'blocked_pid' => 2,
'blocked_application' => 'foo',
'blocked_statement' => 'SELECT 1 FROM products',
'blocking_pid' => 3,
'blocking_application' => 'bar',
'current_statement_in_blocking_process' => 'SELECT 2 FROM products'
]
)

job.perform

expect(TestMetricsReporter).to have_received(:report_event).with(
Postgres::Vacuum::Jobs::MonitorJob::BLOCKED_QUERIES,
database_name: 'postgres_vacuum_monitor_test',
blocked_application: 'foo',
blocked_pid: 2,
blocked_statement: 'SELECT 1 FROM products',
blocking_pid: 3,
blocking_application: 'bar',
current_statement_in_blocking_process: 'SELECT 2 FROM products'
)
end

it "reports connection idle time" do
allow(mock_connection).to receive(:execute).with(Postgres::Vacuum::Monitor::Query.connection_idle_time).and_return(
['max' => 3.1, 'median' => 222.22, 'percentile_90' => 9323.323]
)
it "reports connection state" do
allow(mock_connection).to receive(:execute).with(Postgres::Vacuum::Monitor::Query.connection_state).and_return(
['connection_count' => 4, 'state' => 'idle']
)

job.perform
job.perform

expect(TestMetricsReporter).to have_received(:report_event).with(
Postgres::Vacuum::Jobs::MonitorJob::CONNECTION_IDLE_TIME,
database_name: 'postgres_vacuum_monitor_test',
max: 3.1,
median: 222.22,
percentile_90: 9323.323
)
end
expect(TestMetricsReporter).to have_received(:report_event).with(
Postgres::Vacuum::Jobs::MonitorJob::CONNECTION_STATE,
database_name: 'postgres_vacuum_monitor_test',
connection_count: 4,
state: 'idle'
)
end

context "with multiple connection pools" do
it "reports connection idle time" do
allow(mock_connection).to receive(:execute).with(Postgres::Vacuum::Monitor::Query.connection_idle_time).and_return(
['max' => 3.1, 'median' => 222.22, 'percentile_90' => 9323.323]
)

class SecondPool < ActiveRecord::Base
# might be cleaner to put this in a method if that works. constant is weird.
establish_connection DB_CONFIG['test']
end
job.perform

it "reports once for a single database." do
expect(job.perform).to eq true
expect(mock_connection).to have_received(:execute).exactly(5)
expect(TestMetricsReporter).to have_received(:report_event).with(
Postgres::Vacuum::Jobs::MonitorJob::CONNECTION_IDLE_TIME,
database_name: 'postgres_vacuum_monitor_test',
max: 3.1,
median: 222.22,
percentile_90: 9323.323
)
end

context "to different databases" do
let(:name_change_db_config) { { name: 'my db' } }
context "with multiple connection pools" do

before do
allow(SecondPool.connection_pool.spec).to receive(:config).and_return(name_change_db_config)
class SecondPool < ActiveRecord::Base
# might be cleaner to put this in a method if that works. constant is weird.
establish_connection DB_CONFIG['test']
end

it "reports twice for two databases" do
it "reports once for a single database." do
expect(job.perform).to eq true
expect(mock_connection).to have_received(:execute).exactly(10)
expect(mock_connection).to have_received(:execute).exactly(5)
end

context "to different databases" do
let(:name_change_db_config) { { name: 'my db' } }

before do
allow(SecondPool.connection_pool.spec).to receive(:config).and_return(name_change_db_config)
end

it "reports twice for two databases" do
expect(job.perform).to eq true
expect(mock_connection).to have_received(:execute).exactly(10)
end
end
end
end
Expand Down

0 comments on commit dcb8eae

Please sign in to comment.