Skip to content

Commit

Permalink
Track resources while they are being destroyed
Browse files Browse the repository at this point in the history
  • Loading branch information
cressie176 committed Aug 26, 2023
1 parent 826c5b5 commit a24bdb6
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 31 deletions.
6 changes: 4 additions & 2 deletions lib/Pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ module.exports = class Pool extends EventEmitter {
});
}

async destroy(resource) {
destroy(resource) {
// Do not await - can run in background
new DestroyResourceOperation(this).run(async (op) => {
await this._destroyResource(op, resource);
this._state.removeAcquiredResource(resource);
await this._destroyResource(op, resource);
}).then(() => {
new XPoolOperation(this).run((op) => {
this._checkAcquireQueue(op);
Expand Down Expand Up @@ -207,8 +207,10 @@ module.exports = class Pool extends EventEmitter {

async _destroyResource(op, resource) {
try {
this._state.commenceDestruction(resource);
const task = this._createDestroyTask(op, resource);
await task.execute();
this._state.completeDestruction(resource);
} catch (err) {
this._state.excludeBadResource(resource);
op.failed(err).end();
Expand Down
22 changes: 18 additions & 4 deletions lib/State.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module.exports = class State {
this._acquiringCount = 0;
this._acquired = [];
this._idle = [];
this._destroying = [];
this._bad = [];
this._peakCount = 0;
}
Expand Down Expand Up @@ -46,20 +47,24 @@ module.exports = class State {
return this._idle.length;
}

get destroying() {
return this._destroying.length;
}

get bad() {
return this._bad.length;
}

get size() {
return this.acquiring + this.acquired + this.idle + this.bad;
return this.acquiring + this.acquired + this.idle + this.destroying + this.bad;
}

get spare() {
return Math.max(0, this.idle - this.queued - this.acquiring);
}

get available() {
return this.maxSize - this.acquiring - this.acquired - this.bad;
return this.maxSize - this.acquiring - this.acquired - this.destroying - this.bad;
}

get peak() {
Expand All @@ -82,7 +87,7 @@ module.exports = class State {
}

isEmpty() {
return this.queued + this.acquiring + this.acquired + this.idle + this.bad === 0;
return this.queued + this.acquiring + this.acquired + this.destroying + this.idle + this.bad === 0;
}

isExhausted() {
Expand Down Expand Up @@ -115,8 +120,16 @@ module.exports = class State {
this._removeResource(this._acquired, resource);
}

commenceDestruction(resource) {
this._destroying.push(resource);
}

completeDestruction(resource) {
this._removeResource(this._destroying, resource);
}

excludeBadResource(resource) {
this._removeResource(this._acquired, resource);
this._removeResource(this._destroying, resource);
this._bad.push(resource);
}

Expand All @@ -134,6 +147,7 @@ module.exports = class State {
acquiring: this.acquiring,
acquired: this.acquired,
idle: this.idle,
destroying: this.destroying,
bad: this.bad,
size: this.size,
available: this.available,
Expand Down
87 changes: 62 additions & 25 deletions test/Pool.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -682,10 +682,11 @@ describe('Pool', () => {
const pool = createPool({ factory });

pool.on(DestroyResourceOperation.SUCCEEDED, () => {
const { size, acquired, idle } = pool.stats();
eq(size, 0);
const { acquired, idle, destroying, size } = pool.stats();
eq(acquired, 0);
eq(idle, 0);
eq(destroying, 0);
eq(size, 0);
done();
});

Expand Down Expand Up @@ -822,10 +823,11 @@ describe('Pool', () => {
const pool = createPool({ factory });

pool.once(DestroyResourceOperation.FAILED, () => {
const { size, acquired, bad } = pool.stats();
eq(size, 1);
const { acquired, destroying, bad, size } = pool.stats();
eq(acquired, 0);
eq(destroying, 0);
eq(bad, 1);
eq(size, 1);
done();
});

Expand All @@ -839,10 +841,11 @@ describe('Pool', () => {
const pool = createPool({ factory, destroyTimeout: 100 });

pool.once(DestroyResourceOperation.FAILED, () => {
const { size, acquired, bad } = pool.stats();
eq(size, 1);
const { acquired, destroying, bad, size } = pool.stats();
eq(acquired, 0);
eq(destroying, 0);
eq(bad, 1);
eq(size, 1);
done();
});

Expand All @@ -856,10 +859,11 @@ describe('Pool', () => {
const pool = createPool({ factory, destroyTimeout: 100 });

pool.once(DestroyResourceOperation.NOTICE, () => {
const { size, acquired, bad } = pool.stats();
eq(size, 0);
const { acquired, destroying, bad, size } = pool.stats();
eq(acquired, 0);
eq(destroying, 0);
eq(bad, 0);
eq(size, 0);
done();
});

Expand Down Expand Up @@ -893,11 +897,12 @@ describe('Pool', () => {
const factory = new TestFactory();
const pool = createPool({ factory });

const { queued, acquiring, acquired, idle, bad, size, available, peak } = pool.stats();
const { queued, acquiring, acquired, idle, destroying, bad, size, available, peak } = pool.stats();
eq(queued, 0);
eq(acquiring, 0);
eq(acquired, 0);
eq(idle, 0);
eq(destroying, 0);
eq(bad, 0);
eq(size, 0);
eq(available, Infinity);
Expand All @@ -911,11 +916,12 @@ describe('Pool', () => {

await acquireResources(pool, 3);

const { queued, acquiring, acquired, idle, bad, size, available, peak } = pool.stats();
const { queued, acquiring, acquired, idle, destroying, bad, size, available, peak } = pool.stats();
eq(queued, 0);
eq(acquiring, 0);
eq(acquired, 3);
eq(idle, 0);
eq(destroying, 0);
eq(bad, 0);
eq(size, 3);
eq(available, Infinity);
Expand All @@ -930,11 +936,12 @@ describe('Pool', () => {
const [resource1, resource2, resource3] = await acquireResources(pool, 3);
await releaseResources(pool, [resource1, resource2, resource3]);

const { queued, acquiring, acquired, idle, bad, size, available, peak } = pool.stats();
const { queued, acquiring, acquired, idle, destroying, bad, size, available, peak } = pool.stats();
eq(queued, 0);
eq(acquiring, 0);
eq(acquired, 0);
eq(idle, 3);
eq(destroying, 0);
eq(bad, 0);
eq(size, 3);
eq(available, Infinity);
Expand All @@ -950,28 +957,53 @@ describe('Pool', () => {
pool.acquire();
pool.acquire();

const { queued, acquiring, acquired, idle, bad, size, available, peak } = pool.stats();
const { queued, acquiring, acquired, idle, destroying, bad, size, available, peak } = pool.stats();
eq(queued, 2);
eq(acquiring, 0);
eq(acquired, 1);
eq(idle, 0);
eq(destroying, 0);
eq(bad, 0);
eq(size, 1);
eq(available, 0);
eq(peak, 1);
});

it('should report stats for a pool with destroying resources', async (t, done) => {
const resources = [{ destroyDelay: 200, value: 'R1' }];
const factory = new TestFactory(resources);
const pool = createPool({ factory });

pool.once(DestroyResourceOperation.STARTED, () => {
const { queued, acquiring, acquired, idle, destroying, bad, size, available, peak } = pool.stats();
eq(queued, 0);
eq(acquiring, 0);
eq(acquired, 0);
eq(idle, 0);
eq(destroying, 1);
eq(bad, 0);
eq(size, 1);
eq(available, Infinity);
eq(peak, 1);
done();
});

const resource = await pool.acquire();
pool.destroy(resource);
});

it('should report stats for a pool with bad resources', async (t, done) => {
const resources = ['R1', { destroyError: 'Oh Noes!', value: 'R2' }, 'R3'];
const factory = new TestFactory(resources);
const pool = createPool({ factory });

pool.once(DestroyResourceOperation.FAILED, () => {
const { queued, acquiring, acquired, idle, bad, size, available, peak } = pool.stats();
const { queued, acquiring, acquired, idle, destroying, bad, size, available, peak } = pool.stats();
eq(queued, 0);
eq(acquiring, 0);
eq(acquired, 0);
eq(idle, 0);
eq(destroying, 0);
eq(bad, 1);
eq(size, 1);
eq(available, Infinity);
Expand All @@ -984,49 +1016,53 @@ describe('Pool', () => {
});

it('should report stats for a pool with a mixture of resource states', async (t, done) => {
const resources = ['R1', 'R2', { destroyError: 'Oh Noes!', value: 'R3' }];
const resources = ['R1', 'R2', { destroyDelay: 200, value: 'R3' }, { destroyError: 'Oh Noes!', value: 'R4' }];
const factory = new TestFactory(resources);
const pool = createPool({ factory });

pool.once(DestroyResourceOperation.FAILED, () => {
const { queued, acquiring, acquired, idle, bad, size, available, peak } = pool.stats();
const { queued, acquiring, acquired, idle, destroying, bad, size, available, peak } = pool.stats();
eq(queued, 0);
eq(acquiring, 0);
eq(acquired, 1);
eq(idle, 1);
eq(destroying, 1);
eq(bad, 1);
eq(size, 3);
eq(size, 4);
eq(available, Infinity);
eq(peak, 3);
eq(peak, 4);
done();
});

const [, resource2, resource3] = await acquireResources(pool, 3);
const [, resource2, resource3, resource4] = await acquireResources(pool, 4);
pool.release(resource2);
pool.destroy(resource3);
pool.destroy(resource4);
});

it('should report stats for a pool with a mixture of resource states and a maximum pool size', async (t, done) => {
const resources = ['R1', 'R2', { destroyError: 'Oh Noes!', value: 'R3' }];
const resources = ['R1', 'R2', { destroyDelay: 200, value: 'R3' }, { destroyError: 'Oh Noes!', value: 'R4' }];
const factory = new TestFactory(resources);
const pool = createPool({ factory, maxSize: 10 });

pool.once(DestroyResourceOperation.FAILED, () => {
const { queued, acquiring, acquired, idle, bad, size, available, peak } = pool.stats();
const { queued, acquiring, acquired, idle, destroying, bad, size, available, peak } = pool.stats();
eq(queued, 0);
eq(acquiring, 0);
eq(acquired, 1);
eq(idle, 1);
eq(destroying, 1);
eq(bad, 1);
eq(size, 3);
eq(available, 8);
eq(peak, 3);
eq(size, 4);
eq(available, 7);
eq(peak, 4);
done();
});

const [, resource2, resource3] = await acquireResources(pool, 3);
const [, resource2, resource3, resource4] = await acquireResources(pool, 4);
pool.release(resource2);
pool.destroy(resource3);
pool.destroy(resource4);
});

it('should report the peak pool size', async () => {
Expand All @@ -1037,11 +1073,12 @@ describe('Pool', () => {
const [resource1, resource2, resource3] = await acquireResources(pool, 3);
await destroyResources(pool, [resource1, resource2, resource3]);

const { queued, acquiring, acquired, idle, bad, size, available, peak } = pool.stats();
const { queued, acquiring, acquired, idle, destroying, bad, size, available, peak } = pool.stats();
eq(queued, 0);
eq(acquiring, 0);
eq(acquired, 0);
eq(idle, 0);
eq(destroying, 0);
eq(bad, 0);
eq(size, 0);
eq(peak, 3);
Expand Down

0 comments on commit a24bdb6

Please sign in to comment.