mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-17 23:44:39 -05:00
Removed connection pool instrumentation (#22091)
no issue - This instrumentation is not currently being used and we have a safer method to get this data from the connection pool using prometheus.
This commit is contained in:
parent
049dba469f
commit
45432fa186
3 changed files with 0 additions and 376 deletions
|
@ -1,142 +0,0 @@
|
||||||
class ConnectionPoolInstrumentation {
|
|
||||||
constructor({knex, logging, metrics, config}) {
|
|
||||||
this.knex = knex;
|
|
||||||
this.pool = this.knex.client.pool;
|
|
||||||
this.logging = logging;
|
|
||||||
this.metrics = metrics;
|
|
||||||
this.enabled = config.get('telemetry:connectionPool');
|
|
||||||
this.requestStartTimes = {};
|
|
||||||
this.createStartTimes = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the number of pending creates and acquires plus free and used connections
|
|
||||||
getPoolMetrics() {
|
|
||||||
return {
|
|
||||||
numPendingCreates: this.pool.numPendingCreates(),
|
|
||||||
numPendingAcquires: this.pool.numPendingAcquires(),
|
|
||||||
numFree: this.pool.numFree(),
|
|
||||||
numUsed: this.pool.numUsed()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCreateRequest(eventId) {
|
|
||||||
// Track when the request was submitted for calculating wait time
|
|
||||||
this.createStartTimes[eventId] = Date.now();
|
|
||||||
const poolMetrics = this.getPoolMetrics();
|
|
||||||
this.logging.debug(`[ConnectionPool] Creating a connection. EventID: ${eventId} Pending Creates: ${poolMetrics.numPendingCreates} Free: ${poolMetrics.numFree} Used: ${poolMetrics.numUsed}`);
|
|
||||||
this.metrics.metric('connection-pool', {
|
|
||||||
event: 'create-request',
|
|
||||||
eventId,
|
|
||||||
...poolMetrics
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCreateSuccess(eventId, resource) {
|
|
||||||
// Calculate the time it took to create the connection
|
|
||||||
const timeToCreate = Date.now() - this.createStartTimes[eventId];
|
|
||||||
// Delete the start time so we don't leak memory
|
|
||||||
delete this.createStartTimes[eventId];
|
|
||||||
this.logging.debug(`[ConnectionPool] Created a connection. EventID: ${eventId} Connection ID: ${resource.connectionId} Knex ID: ${resource.__knexUid} Time to Create: ${timeToCreate}ms`);
|
|
||||||
this.metrics.metric('connection-pool', {
|
|
||||||
event: 'create-success',
|
|
||||||
eventId,
|
|
||||||
connectionId: resource.connectionId,
|
|
||||||
knexUid: resource.__knexUid,
|
|
||||||
timeToCreate
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCreateFail(eventId, err) {
|
|
||||||
// Calculate the time it took to create the connection
|
|
||||||
const timeToFail = Date.now() - this.createStartTimes[eventId];
|
|
||||||
// Delete the start time so we don't leak memory
|
|
||||||
delete this.createStartTimes[eventId];
|
|
||||||
const poolMetrics = this.getPoolMetrics();
|
|
||||||
this.logging.error(`[ConnectionPool] Failed to create a connection. EventID: ${eventId} Time to Create: ${timeToFail}ms`, err);
|
|
||||||
this.metrics.metric('connection-pool', {
|
|
||||||
event: 'create-fail',
|
|
||||||
eventId,
|
|
||||||
timeToFail,
|
|
||||||
...poolMetrics
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleAcquireRequest(eventId) {
|
|
||||||
// Track when the request was submitted for calculating wait time
|
|
||||||
this.requestStartTimes[eventId] = Date.now();
|
|
||||||
const poolMetrics = this.getPoolMetrics();
|
|
||||||
this.logging.debug(`[ConnectionPool] Acquiring a connection. EventID: ${eventId} Pending Acquires: ${poolMetrics.numPendingAcquires} Free: ${poolMetrics.numFree} Used: ${poolMetrics.numUsed}`);
|
|
||||||
this.metrics.metric('connection-pool', {
|
|
||||||
event: 'acquire-request',
|
|
||||||
eventId,
|
|
||||||
...poolMetrics
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleAcquireSuccess(eventId, resource) {
|
|
||||||
// Calculate the time it took to acquire the connection
|
|
||||||
const timeToAcquire = Date.now() - this.requestStartTimes[eventId];
|
|
||||||
// Delete the start time so we don't leak memory
|
|
||||||
delete this.requestStartTimes[eventId];
|
|
||||||
// Track when the connection was acquired for calculating lifetime upon release
|
|
||||||
resource.connectionAcquired = Date.now();
|
|
||||||
this.logging.debug(`[ConnectionPool] Acquired a connection. EventID: ${eventId} Connection ID: ${resource.connectionId} Knex Id: ${resource.__knexUid} Time to Acquire: ${timeToAcquire}ms`);
|
|
||||||
this.metrics.metric('connection-pool', {
|
|
||||||
event: 'acquire-success',
|
|
||||||
eventId,
|
|
||||||
connectionId: resource.connectionId,
|
|
||||||
knexUid: resource.__knexUid,
|
|
||||||
timeToAcquire
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleAcquireFail(eventId, err) {
|
|
||||||
// Calculate the time it took to acquire the connection
|
|
||||||
const timeToFail = Date.now() - this.requestStartTimes[eventId];
|
|
||||||
// Delete the start time so we don't leak memory
|
|
||||||
delete this.requestStartTimes[eventId];
|
|
||||||
const poolMetrics = this.getPoolMetrics();
|
|
||||||
this.logging.error(`[ConnectionPool] Failed to acquire a connection. EventID: ${eventId} Time to Acquire: ${timeToFail}ms`, err);
|
|
||||||
this.metrics.metric('connection-pool', {
|
|
||||||
event: 'acquire-fail',
|
|
||||||
eventId,
|
|
||||||
timeToFail,
|
|
||||||
...poolMetrics
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleRelease(resource) {
|
|
||||||
const lifetime = Date.now() - resource.connectionAcquired;
|
|
||||||
this.logging.debug(`[ConnectionPool] Released a connection. Connection ID: ${resource.connectionId} Lifetime: ${lifetime}ms`);
|
|
||||||
this.metrics.metric('connection-pool', {
|
|
||||||
event: 'release',
|
|
||||||
connectionId: resource.connectionId,
|
|
||||||
knexUid: resource.__knexUid,
|
|
||||||
lifetime
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
instrument() {
|
|
||||||
if (this.enabled) {
|
|
||||||
// Check to make sure these event listeners haven't already been added
|
|
||||||
if (this.pool.emitter.eventNames().length === 0) {
|
|
||||||
// Fires when a connection is requested to be created
|
|
||||||
this.pool.on('createRequest', eventId => this.handleCreateRequest(eventId));
|
|
||||||
// Fires when a connection is successfully created
|
|
||||||
this.pool.on('createSuccess', (eventId, resource) => this.handleCreateSuccess(eventId, resource));
|
|
||||||
// Fires when a connection fails to be created
|
|
||||||
this.pool.on('createFail', (eventId, err) => this.handleCreateFail(eventId, err));
|
|
||||||
// Fires when a connection is requested from the pool
|
|
||||||
this.pool.on('acquireRequest', eventId => this.handleAcquireRequest(eventId));
|
|
||||||
// Fires when a connection is allocated from the pool
|
|
||||||
this.pool.on('acquireSuccess', (eventId, resource) => this.handleAcquireSuccess(eventId, resource));
|
|
||||||
// Fires when a connection fails to be allocated from the pool
|
|
||||||
this.pool.on('acquireFail', (eventId, err) => this.handleAcquireFail(eventId, err));
|
|
||||||
// Fires when a connection is released back into the pool
|
|
||||||
this.pool.on('release', resource => this.handleRelease(resource));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = ConnectionPoolInstrumentation;
|
|
|
@ -4,10 +4,8 @@ const os = require('os');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
const logging = require('@tryghost/logging');
|
const logging = require('@tryghost/logging');
|
||||||
const metrics = require('@tryghost/metrics');
|
|
||||||
const config = require('../../../shared/config');
|
const config = require('../../../shared/config');
|
||||||
const errors = require('@tryghost/errors');
|
const errors = require('@tryghost/errors');
|
||||||
const ConnectionPoolInstrumentation = require('./ConnectionPoolInstrumentation');
|
|
||||||
let knexInstance;
|
let knexInstance;
|
||||||
|
|
||||||
// @TODO:
|
// @TODO:
|
||||||
|
@ -64,10 +62,6 @@ function configure(dbConfig) {
|
||||||
|
|
||||||
if (!knexInstance && config.get('database') && config.get('database').client) {
|
if (!knexInstance && config.get('database') && config.get('database').client) {
|
||||||
knexInstance = knex(configure(config.get('database')));
|
knexInstance = knex(configure(config.get('database')));
|
||||||
if (config.get('telemetry:connectionPool')) {
|
|
||||||
const instrumentation = new ConnectionPoolInstrumentation({knex: knexInstance, logging, metrics, config});
|
|
||||||
instrumentation.instrument();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = knexInstance;
|
module.exports = knexInstance;
|
||||||
|
|
|
@ -1,228 +0,0 @@
|
||||||
const sinon = require('sinon');
|
|
||||||
const ConnectionPoolInstrumentation = require('../../../../../core/server/data/db/ConnectionPoolInstrumentation');
|
|
||||||
const should = require('should');
|
|
||||||
var EventEmitter = require('events').EventEmitter;
|
|
||||||
|
|
||||||
describe('ConnectionPoolInstrumentation', function () {
|
|
||||||
afterEach(function () {
|
|
||||||
sinon.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('getPoolMetrics', async function () {
|
|
||||||
const knex = {
|
|
||||||
client: {
|
|
||||||
pool: {
|
|
||||||
numPendingCreates: sinon.stub().returns(1),
|
|
||||||
numPendingAcquires: sinon.stub().returns(2),
|
|
||||||
numFree: sinon.stub().returns(3),
|
|
||||||
numUsed: sinon.stub().returns(4)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const logging = {};
|
|
||||||
const metrics = {};
|
|
||||||
const config = {
|
|
||||||
get: sinon.stub().withArgs('telemetry:connectionPool').returns(true)
|
|
||||||
};
|
|
||||||
const instrumentation = new ConnectionPoolInstrumentation({knex, logging, metrics, config});
|
|
||||||
const result = instrumentation.getPoolMetrics();
|
|
||||||
result.should.eql({
|
|
||||||
numPendingCreates: 1,
|
|
||||||
numPendingAcquires: 2,
|
|
||||||
numFree: 3,
|
|
||||||
numUsed: 4
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle creating a request successfully', async function () {
|
|
||||||
const knex = {
|
|
||||||
client: {
|
|
||||||
pool: {
|
|
||||||
numPendingCreates: sinon.stub().returns(1),
|
|
||||||
numPendingAcquires: sinon.stub().returns(2),
|
|
||||||
numFree: sinon.stub().returns(3),
|
|
||||||
numUsed: sinon.stub().returns(4)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const logging = {
|
|
||||||
debug: sinon.stub()
|
|
||||||
};
|
|
||||||
const metrics = {
|
|
||||||
metric: sinon.stub()
|
|
||||||
};
|
|
||||||
const config = {
|
|
||||||
get: sinon.stub().withArgs('telemetry:connectionPool').returns(true)
|
|
||||||
};
|
|
||||||
const instrumentation = new ConnectionPoolInstrumentation({knex, logging, metrics, config});
|
|
||||||
instrumentation.handleCreateRequest(1);
|
|
||||||
instrumentation.handleCreateSuccess(1, {connectionId: 2, __knexUid: 3});
|
|
||||||
logging.debug.calledTwice.should.be.true();
|
|
||||||
metrics.metric.calledTwice.should.be.true();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle creating a request unsuccessfully', async function () {
|
|
||||||
const knex = {
|
|
||||||
client: {
|
|
||||||
pool: {
|
|
||||||
numPendingCreates: sinon.stub().returns(1),
|
|
||||||
numPendingAcquires: sinon.stub().returns(2),
|
|
||||||
numFree: sinon.stub().returns(3),
|
|
||||||
numUsed: sinon.stub().returns(4)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const logging = {
|
|
||||||
debug: sinon.stub(),
|
|
||||||
error: sinon.stub()
|
|
||||||
};
|
|
||||||
const metrics = {
|
|
||||||
metric: sinon.stub()
|
|
||||||
};
|
|
||||||
const config = {
|
|
||||||
get: sinon.stub().withArgs('telemetry:connectionPool').returns(true)
|
|
||||||
};
|
|
||||||
const instrumentation = new ConnectionPoolInstrumentation({knex, logging, metrics, config});
|
|
||||||
instrumentation.handleCreateRequest(1);
|
|
||||||
instrumentation.handleCreateFail(1, new Error('test'));
|
|
||||||
logging.error.calledOnce.should.be.true();
|
|
||||||
metrics.metric.calledTwice.should.be.true();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle acquiring a connection successfully', async function () {
|
|
||||||
const knex = {
|
|
||||||
client: {
|
|
||||||
pool: {
|
|
||||||
numPendingCreates: sinon.stub().returns(1),
|
|
||||||
numPendingAcquires: sinon.stub().returns(2),
|
|
||||||
numFree: sinon.stub().returns(3),
|
|
||||||
numUsed: sinon.stub().returns(4)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const logging = {
|
|
||||||
debug: sinon.stub()
|
|
||||||
};
|
|
||||||
const metrics = {
|
|
||||||
metric: sinon.stub()
|
|
||||||
};
|
|
||||||
const config = {
|
|
||||||
get: sinon.stub().withArgs('telemetry:connectionPool').returns(true)
|
|
||||||
};
|
|
||||||
const instrumentation = new ConnectionPoolInstrumentation({knex, logging, metrics, config});
|
|
||||||
instrumentation.handleAcquireRequest(1);
|
|
||||||
instrumentation.handleAcquireSuccess(1, {connectionId: 2, __knexUid: 3});
|
|
||||||
logging.debug.calledTwice.should.be.true();
|
|
||||||
metrics.metric.calledTwice.should.be.true();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle acquiring a connection unsuccessfully', async function () {
|
|
||||||
const knex = {
|
|
||||||
client: {
|
|
||||||
pool: {
|
|
||||||
numPendingCreates: sinon.stub().returns(1),
|
|
||||||
numPendingAcquires: sinon.stub().returns(2),
|
|
||||||
numFree: sinon.stub().returns(3),
|
|
||||||
numUsed: sinon.stub().returns(4)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const logging = {
|
|
||||||
debug: sinon.stub(),
|
|
||||||
error: sinon.stub()
|
|
||||||
};
|
|
||||||
const metrics = {
|
|
||||||
metric: sinon.stub()
|
|
||||||
};
|
|
||||||
const config = {
|
|
||||||
get: sinon.stub().withArgs('telemetry:connectionPool').returns(true)
|
|
||||||
};
|
|
||||||
const instrumentation = new ConnectionPoolInstrumentation({knex, logging, metrics, config});
|
|
||||||
instrumentation.handleAcquireRequest(1);
|
|
||||||
instrumentation.handleAcquireFail(1, new Error('test'));
|
|
||||||
logging.error.calledOnce.should.be.true();
|
|
||||||
metrics.metric.calledTwice.should.be.true();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle releasing a connection successfully', async function () {
|
|
||||||
const knex = {
|
|
||||||
client: {
|
|
||||||
pool: {
|
|
||||||
numPendingCreates: sinon.stub().returns(1),
|
|
||||||
numPendingAcquires: sinon.stub().returns(2),
|
|
||||||
numFree: sinon.stub().returns(3),
|
|
||||||
numUsed: sinon.stub().returns(4)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const logging = {
|
|
||||||
debug: sinon.stub()
|
|
||||||
};
|
|
||||||
const metrics = {
|
|
||||||
metric: sinon.stub()
|
|
||||||
};
|
|
||||||
const config = {
|
|
||||||
get: sinon.stub().withArgs('telemetry:connectionPool').returns(true)
|
|
||||||
};
|
|
||||||
const instrumentation = new ConnectionPoolInstrumentation({knex, logging, metrics, config});
|
|
||||||
instrumentation.handleRelease(1);
|
|
||||||
logging.debug.calledOnce.should.be.true();
|
|
||||||
metrics.metric.calledOnce.should.be.true();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should instrument the connection pool if enabled', async function () {
|
|
||||||
const knex = {
|
|
||||||
client: {
|
|
||||||
pool: {
|
|
||||||
numPendingCreates: sinon.stub().returns(1),
|
|
||||||
numPendingAcquires: sinon.stub().returns(2),
|
|
||||||
numFree: sinon.stub().returns(3),
|
|
||||||
numUsed: sinon.stub().returns(4),
|
|
||||||
on: sinon.stub(),
|
|
||||||
emitter: new EventEmitter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const logging = {
|
|
||||||
debug: sinon.stub(),
|
|
||||||
error: sinon.stub()
|
|
||||||
};
|
|
||||||
const metrics = {
|
|
||||||
metric: sinon.stub()
|
|
||||||
};
|
|
||||||
const config = {
|
|
||||||
get: sinon.stub().withArgs('telemetry:connectionPool').returns(true)
|
|
||||||
};
|
|
||||||
const instrumentation = new ConnectionPoolInstrumentation({knex, logging, metrics, config});
|
|
||||||
instrumentation.instrument();
|
|
||||||
knex.client.pool.on.callCount.should.eql(7);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not instrument the connection pool if disabled', async function () {
|
|
||||||
const knex = {
|
|
||||||
client: {
|
|
||||||
pool: {
|
|
||||||
numPendingCreates: sinon.stub().returns(1),
|
|
||||||
numPendingAcquires: sinon.stub().returns(2),
|
|
||||||
numFree: sinon.stub().returns(3),
|
|
||||||
numUsed: sinon.stub().returns(4),
|
|
||||||
on: sinon.stub(),
|
|
||||||
emitter: new EventEmitter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const logging = {
|
|
||||||
debug: sinon.stub(),
|
|
||||||
error: sinon.stub()
|
|
||||||
};
|
|
||||||
const metrics = {
|
|
||||||
metric: sinon.stub()
|
|
||||||
};
|
|
||||||
const config = {
|
|
||||||
get: sinon.stub().withArgs('telemetry:connectionPool').returns(false)
|
|
||||||
};
|
|
||||||
const instrumentation = new ConnectionPoolInstrumentation({knex, logging, metrics, config});
|
|
||||||
instrumentation.instrument();
|
|
||||||
knex.client.pool.on.callCount.should.eql(0);
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Add table
Reference in a new issue