Skip to content

Commit

Permalink
Added autoStart
Browse files Browse the repository at this point in the history
  • Loading branch information
cressie176 committed Aug 26, 2023
1 parent 5e69fad commit 826c5b5
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 10 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"no-unused-vars": ["error", { "varsIgnorePattern": "^debug$", "argsIgnorePattern": "^_\\w+" }],
"no-use-before-define": 0,
"object-curly-newline": 0,
"padded-blocks": 0
"padded-blocks": 0,
"valid-typeof": 0
}
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ try {
| Name | Type | Required | Default | Notes |
| -------------------- | ------- | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| factory | Factory | Y | | An instance of a resource factory. |
| autoStart | boolean | N | false | Initialises the pool automatically. |
| minSize | integer | N | 0 | Sets the minimum pool size. |
| maxSize | integer | N | Infinity | Sets the maximum pool size. |
| maxQueueDepth | integer | N | Infinity | Sets the maximum acquire queue depth, which may be useful to constrain memory usage during exceptionally high peaks. Only meaningful when maxSize is also set. |
Expand Down
2 changes: 1 addition & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export class Pool<T> extends EventEmitter {

export type PoolOptions<T> = {
factory: Factory<T>;
autoStart?: boolean;
minSize?: number;
maxSize?: number;
acquireTimeout: number;
Expand Down Expand Up @@ -51,4 +52,3 @@ export namespace Errors {
class ResourceValidationFailed extends XPoolError {}
class ResourceDestructionFailed extends XPoolError {}
}

6 changes: 5 additions & 1 deletion lib/Pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,27 @@ const { EventEmitter } = require('node:events');
const { scheduler } = require('node:timers/promises');
const TimedTask = require('./TimedTask');
const State = require('./State');
const { validateFactory, validateNumber } = require('./validation');
const { validateFactory, validateBoolean, validateNumber } = require('./validation');
const { ResourceCreationFailed, ResourceValidationFailed, ResourceDestructionFailed, PoolNotRunning } = require('./Errors');
const { XPoolOperation, InitialisePoolOperation, AcquireResourceOperation, CreateResourceOperation, ValidateResourceOperation, ReleaseResourceOperation, WithResourceOperation, DestroyResourceOperation, EvictBadResourcesOperation, ShutdownPoolOperation, DestroySpareResourcesOperation } = require('./Operations');

const DEFAULT_AUTO_START = false;
const DEFAULT_ACQUIRE_RETRY_INTERVAL = 100;

module.exports = class Pool extends EventEmitter {

constructor(options = {}) {
super();
this._factory = validateFactory(options.factory);
this._autoStart = validateBoolean('autoStart', options, false) || DEFAULT_AUTO_START;
this._acquireTimeout = validateNumber('acquireTimeout', options, true, 1);
this._acquireRetryInterval = validateNumber('acquireRetryInterval', options, false, 0) || DEFAULT_ACQUIRE_RETRY_INTERVAL;
this._destroyTimeout = validateNumber('destroyTimeout', options, true, 1);
this._initialiseTimeout = validateNumber('initialiseTimeout', options, false, 1);
this._shutdownTimeout = validateNumber('shutdownTimeout', options, false, 1);
this._state = new State({ maxSize: options.maxSize, minSize: options.minSize, maxQueueDepth: options.maxQueueDepth });

if (this._autoStart) this.initialise();
}

async initialise() {
Expand Down
27 changes: 23 additions & 4 deletions lib/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ function validateFactory(factory) {
return factory;
}

function validateBoolean(name, options, mandatory) {
const value = options[name];
checkMandatory(name, value, mandatory) || checkType(name, value, 'boolean');
return value;
}

function validateNumber(name, options, mandatory, minValue) {
const value = options[name];
if (mandatory && (value === undefined || value === null)) throw new ConfigurationError(`${name} is a required option`);
if (value === undefined || value === null) return;
if (typeof value !== 'number') throw new ConfigurationError(`The ${name} option must be a number`);
if (value < minValue) throw new ConfigurationError(`The ${name} option must be at least ${minValue}`);
checkMandatory(name, value, mandatory) || (checkType(name, value, 'number') && checkMinValue(name, value, minValue));
return value;
}

Expand All @@ -24,8 +27,24 @@ function validateUpperBoundary(name1, name2, options) {
if (value1 > value2) throw new ConfigurationError(`The ${name1} option must be less than or equal to ${name2}`);
}

function checkMandatory(name, value, mandatory) {
if (mandatory && (value === undefined || value === null)) throw new ConfigurationError(`${name} is a required option`);
if (value === undefined || value === null) return true;
}

function checkType(name, value, type) {
if (typeof value !== type) throw new ConfigurationError(`The ${name} option must be a ${type}`);
return true;
}

function checkMinValue(name, value, minValue) {
if (value < minValue) throw new ConfigurationError(`The ${name} option must be at least ${minValue}`);
return true;
}

module.exports = {
validateFactory,
validateBoolean,
validateNumber,
validateUpperBoundary,
};
31 changes: 28 additions & 3 deletions test/Pool.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const { describe, it } = require('zunit');
const TestFactory = require('./lib/TestFactory');
const {
Pool,
Operations: { XPoolEvent, CreateResourceOperation, ValidateResourceOperation, ReleaseResourceOperation, DestroyResourceOperation },
Operations: { XPoolEvent, InitialisePoolOperation, CreateResourceOperation, ValidateResourceOperation, ReleaseResourceOperation, DestroyResourceOperation },
Errors: { XPoolError, ConfigurationError, ResourceCreationFailed, ResourceValidationFailed, ResourceDestructionFailed, OperationTimedout, PoolNotRunning, MaxQueueDepthExceeded },
} = require('../index');

Expand Down Expand Up @@ -51,6 +51,31 @@ describe('Pool', () => {
});
});

describe('autoStart', () => {

it('should require autoStart to be a boolean', () => {
const factory = new TestFactory();
throws(() => new Pool({ factory, acquireTimeout: 1000, destroyTimeout: 1000, autoStart: 'false' }), (err) => {
eq(err.code, ConfigurationError.code);
eq(err.message, 'The autoStart option must be a boolean. Please read the documentation at https://acuminous.github.io/x-pool');
return true;
});
});

it('should initialise the pool when set', async (t, done) => {
const resources = ['R1', 'R2', 'R3', 'R4', 'R5'];
const factory = new TestFactory(resources);
const pool = createPool({ factory, minSize: 5, autoStart: true });

pool.once(InitialisePoolOperation.SUCCEEDED, () => {
const { size, idle } = pool.stats();
eq(size, 5);
eq(idle, 5);
done();
});
});
});

describe('maxSize', () => {

it('should require maxSize to be a number', () => {
Expand Down Expand Up @@ -1256,8 +1281,8 @@ describe('Pool', () => {
});
});

function createPool({ factory, minSize, maxSize, maxQueueDepth, initialiseTimeout, acquireTimeout = 1000, acquireRetryInterval, destroyTimeout = 1000 }) {
const pool = new Pool({ factory, minSize, maxSize, maxQueueDepth, initialiseTimeout, acquireTimeout, acquireRetryInterval, destroyTimeout });
function createPool({ factory, autoStart, minSize, maxSize, maxQueueDepth, initialiseTimeout, acquireTimeout = 1000, acquireRetryInterval, destroyTimeout = 1000 }) {
const pool = new Pool({ factory, autoStart, minSize, maxSize, maxQueueDepth, initialiseTimeout, acquireTimeout, acquireRetryInterval, destroyTimeout });
pool.on(XPoolEvent, ({ message }) => {
debug(message);
});
Expand Down

0 comments on commit 826c5b5

Please sign in to comment.