Change endpoint from persons to people

This commit is contained in:
xfarrow
2025-03-23 21:00:08 +01:00
parent 4ae263662c
commit d005193f63
7158 changed files with 700476 additions and 735 deletions

22
backend/apis/nodejs/node_modules/tarn/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Vincit Oy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

193
backend/apis/nodejs/node_modules/tarn/README.md generated vendored Normal file
View File

@ -0,0 +1,193 @@
[![Build Status](https://travis-ci.org/Vincit/tarn.js.svg?branch=master)](https://travis-ci.org/Vincit/tarn.js)
## Why yet another resource pool?
Tarn is focused on robustness and ability to recover from errors. Tarn has timeouts for all operations
that can fail or timeout so that you should never end up with pool full of crap. Tarn has a comprehensive
test suite and we are committed to adding tests and fixing all bugs that are found.
Tarn will always remain simple.
## Install
```
npm install tarn
```
## Usage
```js
const { Pool, TimeoutError } = require('tarn');
const pool = new Pool({
// Function that creates a resource. You can either pass the resource
// to the callback(error, resource) or return a promise that resolves the resource
// (but not both) Callback syntax will be deprecated at some point.
create: cb => {
cb(null, new SomeResource());
},
// Validates a connection before it is used. Return true or false
// from it. If false is returned, the resource is destroyed and
// another one is acquired. Should return a Promise if validate is
// an async function.
validate: resource => {
return true;
},
// Function that destroys a resource, should return a promise if
// destroying is an asynchronous operation.
destroy: someResource => {
someResource.cleanup();
},
// logger function, noop by default
log: (message, logLevel) => console.log(`${logLevel}: ${message}`)
// minimum size
min: 2,
// maximum size
max: 10,
// acquire promises are rejected after this many milliseconds
// if a resource cannot be acquired
acquireTimeoutMillis: 30000,
// create operations are cancelled after this many milliseconds
// if a resource cannot be acquired
createTimeoutMillis: 30000,
// destroy operations are awaited for at most this many milliseconds
// new resources will be created after this timeout
destroyTimeoutMillis: 5000,
// free resouces are destroyed after this many milliseconds
idleTimeoutMillis: 30000,
// how often to check for idle resources to destroy
reapIntervalMillis: 1000,
// how long to idle after failed create before trying again
createRetryIntervalMillis: 200,
// If true, when a create fails, the first pending acquire is
// rejected with the error. If this is false (the default) then
// create is retried until acquireTimeoutMillis milliseconds has
// passed.
propagateCreateError: false
});
// acquires a resource. The promise is rejected with `tarn.TimeoutError`
// after `acquireTimeoutMillis` if a resource could not be acquired.
const acquire = pool.acquire();
// acquire can be aborted using the abort method.
// If acquire had triggered creating a new resource in the pool
// creation will continue and it is not aborted.
acquire.abort();
// the acquire object has a promise property that gets resolved with
// the acquired resource
try {
const resource = await acquire.promise;
} catch (err) {
// if the acquire times out an error of class TimeoutError is thrown
if (err instanceof TimeoutError) {
console.log('timeout');
}
}
// releases the resource.
pool.release(resource);
// returns the number of non-free resources
pool.numUsed();
// returns the number of free resources
pool.numFree();
// how many acquires are waiting for a resource to be released
pool.numPendingAcquires();
// how many asynchronous create calls are running
pool.numPendingCreates();
// waits for all resources to be returned to the pool and destroys them.
// pool cannot be used after this.
await pool.destroy();
// The following examples add synchronous event handlers. For example, to
// allow externally collecting pool behaviour diagnostic data.
// If any of these hooks fail, all errors are caught and warnings are logged.
// resource is acquired from pool
pool.on('acquireRequest', eventId => {});
pool.on('acquireSuccess', (eventId, resource) => {});
pool.on('acquireFail', (eventId, err) => {});
// resource returned to pool
pool.on('release', resource => {});
// resource was created and added to the pool
pool.on('createRequest', eventId => {});
pool.on('createSuccess', (eventId, resource) => {});
pool.on('createFail', (eventId, err) => {});
// resource is destroyed and evicted from pool
// resource may or may not be invalid when destroySuccess / destroyFail is called
pool.on('destroyRequest', (eventId, resource) => {});
pool.on('destroySuccess', (eventId, resource) => {});
pool.on('destroyFail', (eventId, resource, err) => {});
// when internal reaping event clock is activated / deactivated
pool.on('startReaping', () => {});
pool.on('stopReaping', () => {});
// pool is destroyed (after poolDestroySuccess all event handlers are also cleared)
pool.on('poolDestroyRequest', eventId => {});
pool.on('poolDestroySuccess', eventId => {});
// remove single event listener
pool.removeListener(eventName, listener);
// remove all listeners from an event
pool.removeAllListeners(eventName);
```
## Changelog
### Master
### 3.0.2 2021-11-29
- Valid resources with rejected acquires are returned to the pool #68
### 3.0.1 2020-10-25
- Added triggering missing createFail event on timeout error - fixes #57
### 3.0.0 2020-04-18
- Async validation support, now validation resource function can return a promise #45
- Fixed releasing abandoned resource after creation when create timeout #48
Released as major version, because async validation support did require lots of internal changes, which may cause subtle difference in behavior.
### 2.0.0 2019-06-02
- Accidentally published breaking changes in 1.2.0. Unpublished it and published again with correct version number 2.0.0 #33
### 1.2.0 2019-06-02 (UNPUBLISHED)
- Passing unknown options throws an error #19 #32
- Diagnostic event handlers to allow monitoring pool behaviour #14 #23
- Dropped node 6 support #25 #28
- pool.destroy() now always waits for all pending destroys to finish before resolving #29
### 1.1.5 2019-04-06
- Added changelog #22
- Handle opt.destroy() being a promise with destroyTimeout #16
- Explicitly silence bluebird warnings #17
- Add strict typings via TypeScript #10

View File

@ -0,0 +1,12 @@
import { Deferred } from './utils';
export declare class PendingOperation<T> {
protected timeoutMillis: number;
possibleTimeoutCause: Error | null;
promise: Promise<T>;
isRejected: boolean;
protected deferred: Deferred<T>;
constructor(timeoutMillis: number);
abort(): void;
reject(err: Error): void;
resolve(value: T): void;
}

View File

@ -0,0 +1,48 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const TimeoutError_1 = require("./TimeoutError");
const utils_1 = require("./utils");
class PendingOperation {
constructor(timeoutMillis) {
this.timeoutMillis = timeoutMillis;
this.deferred = utils_1.defer();
this.possibleTimeoutCause = null;
this.isRejected = false;
this.promise = timeout(this.deferred.promise, timeoutMillis).catch(err => {
if (err instanceof TimeoutError_1.TimeoutError) {
if (this.possibleTimeoutCause) {
err = new TimeoutError_1.TimeoutError(this.possibleTimeoutCause.message);
}
else {
err = new TimeoutError_1.TimeoutError('operation timed out for an unknown reason');
}
}
this.isRejected = true;
return Promise.reject(err);
});
}
abort() {
this.reject(new Error('aborted'));
}
reject(err) {
this.deferred.reject(err);
}
resolve(value) {
this.deferred.resolve(value);
}
}
exports.PendingOperation = PendingOperation;
function timeout(promise, time) {
return new Promise((resolve, reject) => {
const timeoutHandle = setTimeout(() => reject(new TimeoutError_1.TimeoutError()), time);
promise
.then(result => {
clearTimeout(timeoutHandle);
resolve(result);
})
.catch(err => {
clearTimeout(timeoutHandle);
reject(err);
});
});
}

98
backend/apis/nodejs/node_modules/tarn/dist/Pool.d.ts generated vendored Normal file
View File

@ -0,0 +1,98 @@
/// <reference types="node" />
import { PendingOperation } from './PendingOperation';
import { Resource } from './Resource';
import { EventEmitter } from 'events';
export interface PoolOptions<T> {
create: CallbackOrPromise<T>;
destroy: (resource: T) => any;
min: number;
max: number;
acquireTimeoutMillis?: number;
createTimeoutMillis?: number;
destroyTimeoutMillis?: number;
idleTimeoutMillis?: number;
createRetryIntervalMillis?: number;
reapIntervalMillis?: number;
log?: (msg: string) => any;
validate?: (resource: T) => boolean;
propagateCreateError?: boolean;
}
export declare class Pool<T> {
protected min: number;
protected max: number;
protected used: Resource<T>[];
protected free: Resource<T>[];
protected pendingCreates: PendingOperation<T>[];
protected pendingAcquires: PendingOperation<T>[];
protected pendingDestroys: PendingOperation<T>[];
protected pendingValidations: PendingOperation<T>[];
protected interval: NodeJS.Timer | null;
protected destroyed: boolean;
protected propagateCreateError: boolean;
protected idleTimeoutMillis: number;
protected createRetryIntervalMillis: number;
protected reapIntervalMillis: number;
protected createTimeoutMillis: number;
protected destroyTimeoutMillis: number;
protected acquireTimeoutMillis: number;
protected log: (msg: string, level: 'warn') => any;
protected creator: CallbackOrPromise<T>;
protected destroyer: (resource: T) => any;
protected validate: (resource: T) => boolean;
protected eventId: number;
protected emitter: EventEmitter;
constructor(opt: PoolOptions<T>);
numUsed(): number;
numFree(): number;
numPendingAcquires(): number;
numPendingValidations(): number;
numPendingCreates(): number;
acquire(): PendingOperation<T>;
release(resource: T): boolean;
isEmpty(): boolean;
/**
* Reaping cycle.
*/
check(): void;
destroy(): Promise<import("./PromiseInspection").PromiseInspection<unknown> | import("./PromiseInspection").PromiseInspection<void>>;
on(eventName: 'acquireRequest', handler: (eventId: number) => void): void;
on(eventName: 'acquireSuccess', handler: (eventId: number, resource: T) => void): void;
on(eventName: 'acquireFail', handler: (eventId: number, err: Error) => void): void;
on(eventName: 'release', handler: (resource: T) => void): void;
on(eventName: 'createRequest', handler: (eventId: number) => void): void;
on(eventName: 'createSuccess', handler: (eventId: number, resource: T) => void): void;
on(eventName: 'createFail', handler: (eventId: number, err: Error) => void): void;
on(eventName: 'destroyRequest', handler: (eventId: number, resource: T) => void): void;
on(eventName: 'destroySuccess', handler: (eventId: number, resource: T) => void): void;
on(eventName: 'destroyFail', handler: (eventId: number, resource: T, err: Error) => void): void;
on(eventName: 'startReaping', handler: () => void): void;
on(eventName: 'stopReaping', handler: () => void): void;
on(eventName: 'poolDestroyRequest', handler: (eventId: number) => void): void;
on(eventName: 'poolDestroySuccess', handler: (eventId: number) => void): void;
removeListener(event: string | symbol, listener: (...args: any[]) => void): void;
removeAllListeners(event?: string | symbol | undefined): void;
/**
* The most important method that is called always when resources
* are created / destroyed / acquired / released. In other words
* every time when resources are moved from used to free or vice
* versa.
*
* Either assigns free resources to pendingAcquires or creates new
* resources if there is room for it in the pool.
*/
_tryAcquireOrCreate(): void;
_hasFreeResources(): boolean;
_doAcquire(): void;
_canAcquire(): boolean;
_validateResource(resource: T): Promise<boolean>;
_shouldCreateMoreResources(): boolean;
_doCreate(): void;
_create(): PendingOperation<T>;
_destroy(resource: T): Promise<void | T>;
_logDestroyerError(eventId: number, resource: T, err: Error): void;
_startReaping(): void;
_stopReaping(): void;
_executeEventHandlers(eventName: string, ...args: any): void;
}
export declare type Callback<T> = (err: Error | null, resource: T) => any;
export declare type CallbackOrPromise<T> = (cb: Callback<T>) => any | (() => Promise<T>);

516
backend/apis/nodejs/node_modules/tarn/dist/Pool.js generated vendored Normal file
View File

@ -0,0 +1,516 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const PendingOperation_1 = require("./PendingOperation");
const Resource_1 = require("./Resource");
const utils_1 = require("./utils");
const events_1 = require("events");
const timers_1 = require("timers");
class Pool {
constructor(opt) {
this.destroyed = false;
this.emitter = new events_1.EventEmitter();
opt = opt || {};
if (!opt.create) {
throw new Error('Tarn: opt.create function most be provided');
}
if (!opt.destroy) {
throw new Error('Tarn: opt.destroy function most be provided');
}
if (typeof opt.min !== 'number' || opt.min < 0 || opt.min !== Math.round(opt.min)) {
throw new Error('Tarn: opt.min must be an integer >= 0');
}
if (typeof opt.max !== 'number' || opt.max <= 0 || opt.max !== Math.round(opt.max)) {
throw new Error('Tarn: opt.max must be an integer > 0');
}
if (opt.min > opt.max) {
throw new Error('Tarn: opt.max is smaller than opt.min');
}
if (!utils_1.checkOptionalTime(opt.acquireTimeoutMillis)) {
throw new Error('Tarn: invalid opt.acquireTimeoutMillis ' + JSON.stringify(opt.acquireTimeoutMillis));
}
if (!utils_1.checkOptionalTime(opt.createTimeoutMillis)) {
throw new Error('Tarn: invalid opt.createTimeoutMillis ' + JSON.stringify(opt.createTimeoutMillis));
}
if (!utils_1.checkOptionalTime(opt.destroyTimeoutMillis)) {
throw new Error('Tarn: invalid opt.destroyTimeoutMillis ' + JSON.stringify(opt.destroyTimeoutMillis));
}
if (!utils_1.checkOptionalTime(opt.idleTimeoutMillis)) {
throw new Error('Tarn: invalid opt.idleTimeoutMillis ' + JSON.stringify(opt.idleTimeoutMillis));
}
if (!utils_1.checkOptionalTime(opt.reapIntervalMillis)) {
throw new Error('Tarn: invalid opt.reapIntervalMillis ' + JSON.stringify(opt.reapIntervalMillis));
}
if (!utils_1.checkOptionalTime(opt.createRetryIntervalMillis)) {
throw new Error('Tarn: invalid opt.createRetryIntervalMillis ' +
JSON.stringify(opt.createRetryIntervalMillis));
}
const allowedKeys = {
create: true,
validate: true,
destroy: true,
log: true,
min: true,
max: true,
acquireTimeoutMillis: true,
createTimeoutMillis: true,
destroyTimeoutMillis: true,
idleTimeoutMillis: true,
reapIntervalMillis: true,
createRetryIntervalMillis: true,
propagateCreateError: true
};
for (const key of Object.keys(opt)) {
if (!allowedKeys[key]) {
throw new Error(`Tarn: unsupported option opt.${key}`);
}
}
this.creator = opt.create;
this.destroyer = opt.destroy;
this.validate = typeof opt.validate === 'function' ? opt.validate : () => true;
this.log = opt.log || (() => { });
this.acquireTimeoutMillis = opt.acquireTimeoutMillis || 30000;
this.createTimeoutMillis = opt.createTimeoutMillis || 30000;
this.destroyTimeoutMillis = opt.destroyTimeoutMillis || 5000;
this.idleTimeoutMillis = opt.idleTimeoutMillis || 30000;
this.reapIntervalMillis = opt.reapIntervalMillis || 1000;
this.createRetryIntervalMillis = opt.createRetryIntervalMillis || 200;
this.propagateCreateError = !!opt.propagateCreateError;
this.min = opt.min;
this.max = opt.max;
// All the resources, which are either already acquired or which are
// considered for being passed to acquire in async validation phase.
this.used = [];
// All the resources, which are either just created and free or returned
// back to pool after using.
this.free = [];
this.pendingCreates = [];
this.pendingAcquires = [];
this.pendingDestroys = [];
// When acquire is pending, but also still in validation phase
this.pendingValidations = [];
this.destroyed = false;
this.interval = null;
this.eventId = 1;
}
numUsed() {
return this.used.length;
}
numFree() {
return this.free.length;
}
numPendingAcquires() {
return this.pendingAcquires.length;
}
numPendingValidations() {
return this.pendingValidations.length;
}
numPendingCreates() {
return this.pendingCreates.length;
}
acquire() {
const eventId = this.eventId++;
this._executeEventHandlers('acquireRequest', eventId);
const pendingAcquire = new PendingOperation_1.PendingOperation(this.acquireTimeoutMillis);
this.pendingAcquires.push(pendingAcquire);
// If the acquire fails for whatever reason
// remove it from the pending queue.
pendingAcquire.promise = pendingAcquire.promise
.then(resource => {
this._executeEventHandlers('acquireSuccess', eventId, resource);
return resource;
})
.catch(err => {
this._executeEventHandlers('acquireFail', eventId, err);
remove(this.pendingAcquires, pendingAcquire);
return Promise.reject(err);
});
this._tryAcquireOrCreate();
return pendingAcquire;
}
release(resource) {
this._executeEventHandlers('release', resource);
for (let i = 0, l = this.used.length; i < l; ++i) {
const used = this.used[i];
if (used.resource === resource) {
this.used.splice(i, 1);
this.free.push(used.resolve());
this._tryAcquireOrCreate();
return true;
}
}
return false;
}
isEmpty() {
return ([
this.numFree(),
this.numUsed(),
this.numPendingAcquires(),
this.numPendingValidations(),
this.numPendingCreates()
].reduce((total, value) => total + value) === 0);
}
/**
* Reaping cycle.
*/
check() {
const timestamp = utils_1.now();
const newFree = [];
const minKeep = this.min - this.used.length;
const maxDestroy = this.free.length - minKeep;
let numDestroyed = 0;
this.free.forEach(free => {
if (utils_1.duration(timestamp, free.timestamp) >= this.idleTimeoutMillis &&
numDestroyed < maxDestroy) {
numDestroyed++;
this._destroy(free.resource);
}
else {
newFree.push(free);
}
});
this.free = newFree;
// Pool is completely empty, stop reaping.
// Next .acquire will start reaping interval again.
if (this.isEmpty()) {
this._stopReaping();
}
}
destroy() {
const eventId = this.eventId++;
this._executeEventHandlers('poolDestroyRequest', eventId);
this._stopReaping();
this.destroyed = true;
// First wait for all the pending creates get ready.
return utils_1.reflect(Promise.all(this.pendingCreates.map(create => utils_1.reflect(create.promise)))
.then(() => {
// eslint-disable-next-line
return new Promise((resolve, reject) => {
// poll every 100ms and wait that all validations are ready
if (this.numPendingValidations() === 0) {
resolve();
return;
}
const interval = setInterval(() => {
if (this.numPendingValidations() === 0) {
timers_1.clearInterval(interval);
resolve();
}
}, 100);
});
})
.then(() => {
// Wait for all the used resources to be freed.
return Promise.all(this.used.map(used => utils_1.reflect(used.promise)));
})
.then(() => {
// Abort all pending acquires.
return Promise.all(this.pendingAcquires.map(acquire => {
acquire.abort();
return utils_1.reflect(acquire.promise);
}));
})
.then(() => {
// Now we can destroy all the freed resources.
return Promise.all(this.free.map(free => utils_1.reflect(this._destroy(free.resource))));
})
.then(() => {
// Also wait rest of the pending destroys to finish
return Promise.all(this.pendingDestroys.map(pd => pd.promise));
})
.then(() => {
this.free = [];
this.pendingAcquires = [];
})).then(res => {
this._executeEventHandlers('poolDestroySuccess', eventId);
this.emitter.removeAllListeners();
return res;
});
}
on(event, listener) {
this.emitter.on(event, listener);
}
removeListener(event, listener) {
this.emitter.removeListener(event, listener);
}
removeAllListeners(event) {
this.emitter.removeAllListeners(event);
}
/**
* The most important method that is called always when resources
* are created / destroyed / acquired / released. In other words
* every time when resources are moved from used to free or vice
* versa.
*
* Either assigns free resources to pendingAcquires or creates new
* resources if there is room for it in the pool.
*/
_tryAcquireOrCreate() {
if (this.destroyed) {
return;
}
if (this._hasFreeResources()) {
this._doAcquire();
}
else if (this._shouldCreateMoreResources()) {
this._doCreate();
}
}
_hasFreeResources() {
return this.free.length > 0;
}
_doAcquire() {
// Acquire as many pending acquires as possible concurrently
while (this._canAcquire()) {
// To allow async validation, we actually need to move free resource
// and pending acquire temporary from their respective arrays and depending
// on validation result to either leave the free resource to used resources array
// or destroy the free resource if validation did fail.
const pendingAcquire = this.pendingAcquires.shift();
const free = this.free.pop();
if (free === undefined || pendingAcquire === undefined) {
const errMessage = 'this.free was empty while trying to acquire resource';
this.log(`Tarn: ${errMessage}`, 'warn');
throw new Error(`Internal error, should never happen. ${errMessage}`);
}
// Make sure that pendingAcquire that is being validated is not lost and
// can be freed when pool is destroyed.
this.pendingValidations.push(pendingAcquire);
// Must be added here pre-emptively to prevent logic that decides
// if new resources are created will keep on working correctly.
this.used.push(free);
// if acquire fails also pending validation, must be aborted so that pre reserved
// resource will be returned to free resources immediately
const abortAbleValidation = new PendingOperation_1.PendingOperation(this.acquireTimeoutMillis);
// eslint-disable-next-line
pendingAcquire.promise.catch(err => {
abortAbleValidation.abort();
});
abortAbleValidation.promise
.catch(err => {
// There's nothing we can do here but log the error. This would otherwise
// leak out as an unhandled exception.
this.log('Tarn: resource validator threw an exception ' + err.stack, 'warn');
return false;
})
.then(validationSuccess => {
try {
if (validationSuccess && !pendingAcquire.isRejected) {
// At least one active resource exist, start reaping.
this._startReaping();
pendingAcquire.resolve(free.resource);
}
else {
remove(this.used, free);
// Only destroy the resource if the validation has failed
if (!validationSuccess) {
this._destroy(free.resource);
// Since we destroyed an invalid resource and were not able to fulfill
// all the pending acquires, we may need to create new ones or at
// least run this acquire loop again to verify it. But not immediately
// to prevent starving event loop.
setTimeout(() => {
this._tryAcquireOrCreate();
}, 0);
}
else {
this.free.push(free);
}
// is acquire was canceled, failed or timed out already
// no need to return it to pending queries
if (!pendingAcquire.isRejected) {
this.pendingAcquires.unshift(pendingAcquire);
}
}
}
finally {
remove(this.pendingValidations, pendingAcquire);
}
});
// try to validate
this._validateResource(free.resource)
.then(validationSuccess => {
abortAbleValidation.resolve(validationSuccess);
})
.catch(err => {
abortAbleValidation.reject(err);
});
}
}
_canAcquire() {
return this.free.length > 0 && this.pendingAcquires.length > 0;
}
_validateResource(resource) {
try {
return Promise.resolve(this.validate(resource));
}
catch (err) {
// prevent leaking of sync exception
return Promise.reject(err);
}
}
_shouldCreateMoreResources() {
return (this.used.length + this.pendingCreates.length < this.max &&
this.pendingCreates.length < this.pendingAcquires.length);
}
_doCreate() {
const pendingAcquiresBeforeCreate = this.pendingAcquires.slice();
const pendingCreate = this._create();
pendingCreate.promise
.then(() => {
// Not returned on purpose.
this._tryAcquireOrCreate();
return null;
})
.catch(err => {
if (this.propagateCreateError && this.pendingAcquires.length !== 0) {
// If propagateCreateError is true, we don't retry the create
// but reject the first pending acquire immediately. Intentionally
// use `this.pendingAcquires` instead of `pendingAcquiresBeforeCreate`
// in case some acquires in pendingAcquiresBeforeCreate have already
// been resolved.
this.pendingAcquires[0].reject(err);
}
// Save the create error to all pending acquires so that we can use it
// as the error to reject the acquire if it times out.
pendingAcquiresBeforeCreate.forEach(pendingAcquire => {
pendingAcquire.possibleTimeoutCause = err;
});
// Not returned on purpose.
utils_1.delay(this.createRetryIntervalMillis).then(() => this._tryAcquireOrCreate());
});
}
_create() {
const eventId = this.eventId++;
this._executeEventHandlers('createRequest', eventId);
const pendingCreate = new PendingOperation_1.PendingOperation(this.createTimeoutMillis);
// If an error occurs (likely a create timeout) remove this creation from
// the list of pending creations so we try to create a new one.
pendingCreate.promise = pendingCreate.promise.catch(err => {
if (remove(this.pendingCreates, pendingCreate)) {
// TODO: figure out more consistent way for different error handlers in next rewrite
this._executeEventHandlers('createFail', eventId, err);
}
throw err;
});
this.pendingCreates.push(pendingCreate);
callbackOrPromise(this.creator)
.then(resource => {
if (pendingCreate.isRejected) {
this.destroyer(resource);
return null;
}
remove(this.pendingCreates, pendingCreate);
this.free.push(new Resource_1.Resource(resource));
// Not returned on purpose.
pendingCreate.resolve(resource);
this._executeEventHandlers('createSuccess', eventId, resource);
return null;
})
.catch(err => {
if (pendingCreate.isRejected) {
return null;
}
if (remove(this.pendingCreates, pendingCreate)) {
this._executeEventHandlers('createFail', eventId, err);
}
// Not returned on purpose.
pendingCreate.reject(err);
return null;
});
return pendingCreate;
}
_destroy(resource) {
const eventId = this.eventId++;
this._executeEventHandlers('destroyRequest', eventId, resource);
// this.destroyer can be both synchronous and asynchronous.
// so we wrap it to promise to get all exceptions through same pipeline
const pendingDestroy = new PendingOperation_1.PendingOperation(this.destroyTimeoutMillis);
const retVal = Promise.resolve().then(() => this.destroyer(resource));
retVal
.then(() => {
pendingDestroy.resolve(resource);
})
.catch((err) => {
pendingDestroy.reject(err);
});
this.pendingDestroys.push(pendingDestroy);
// In case of an error there's nothing we can do here but log it.
return pendingDestroy.promise
.then(res => {
this._executeEventHandlers('destroySuccess', eventId, resource);
return res;
})
.catch(err => this._logDestroyerError(eventId, resource, err))
.then(res => {
const index = this.pendingDestroys.findIndex(pd => pd === pendingDestroy);
this.pendingDestroys.splice(index, 1);
return res;
});
}
_logDestroyerError(eventId, resource, err) {
this._executeEventHandlers('destroyFail', eventId, resource, err);
this.log('Tarn: resource destroyer threw an exception ' + err.stack, 'warn');
}
_startReaping() {
if (!this.interval) {
this._executeEventHandlers('startReaping');
this.interval = setInterval(() => this.check(), this.reapIntervalMillis);
}
}
_stopReaping() {
if (this.interval !== null) {
this._executeEventHandlers('stopReaping');
timers_1.clearInterval(this.interval);
}
this.interval = null;
}
_executeEventHandlers(eventName, ...args) {
const listeners = this.emitter.listeners(eventName);
// just calling .emit() would stop running rest of the listeners if one them fails
listeners.forEach(listener => {
try {
listener(...args);
}
catch (err) {
// There's nothing we can do here but log the error. This would otherwise
// leak out as an unhandled exception.
this.log(`Tarn: event handler "${eventName}" threw an exception ${err.stack}`, 'warn');
}
});
}
}
exports.Pool = Pool;
function remove(arr, item) {
const idx = arr.indexOf(item);
if (idx === -1) {
return false;
}
else {
arr.splice(idx, 1);
return true;
}
}
function callbackOrPromise(func) {
return new Promise((resolve, reject) => {
const callback = (err, resource) => {
if (err) {
reject(err);
}
else {
resolve(resource);
}
};
utils_1.tryPromise(() => func(callback))
.then(res => {
// If the result is falsy, we assume that the callback will
// be called instead of interpreting the falsy value as a
// result value.
if (res) {
resolve(res);
}
})
.catch(err => {
reject(err);
});
});
}

View File

@ -0,0 +1,16 @@
export declare type PromiseInspectionArgs<T> = {
value: T;
error?: Error;
} | {
value?: T;
error: Error;
};
export declare class PromiseInspection<T> {
_value: T | void;
_error: Error | void;
constructor(args: PromiseInspectionArgs<T>);
value(): void | T;
reason(): void | Error;
isRejected(): boolean;
isFulfilled(): boolean;
}

View File

@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class PromiseInspection {
constructor(args) {
this._value = args.value;
this._error = args.error;
}
value() {
return this._value;
}
reason() {
return this._error;
}
isRejected() {
return !!this._error;
}
isFulfilled() {
return !!this._value;
}
}
exports.PromiseInspection = PromiseInspection;

View File

@ -0,0 +1,9 @@
import { Deferred } from './utils';
export declare class Resource<T> {
resource: T;
readonly timestamp: number;
protected deferred: Deferred<void>;
constructor(resource: T);
get promise(): Promise<void>;
resolve(): Resource<T>;
}

19
backend/apis/nodejs/node_modules/tarn/dist/Resource.js generated vendored Normal file
View File

@ -0,0 +1,19 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("./utils");
class Resource {
constructor(resource) {
this.resource = resource;
this.resource = resource;
this.timestamp = utils_1.now();
this.deferred = utils_1.defer();
}
get promise() {
return this.deferred.promise;
}
resolve() {
this.deferred.resolve(undefined);
return new Resource(this.resource);
}
}
exports.Resource = Resource;

View File

@ -0,0 +1,2 @@
export declare class TimeoutError extends Error {
}

View File

@ -0,0 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class TimeoutError extends Error {
}
exports.TimeoutError = TimeoutError;

3
backend/apis/nodejs/node_modules/tarn/dist/tarn.d.ts generated vendored Normal file
View File

@ -0,0 +1,3 @@
import { Pool } from './Pool';
import { TimeoutError } from './TimeoutError';
export { Pool, TimeoutError };

10
backend/apis/nodejs/node_modules/tarn/dist/tarn.js generated vendored Normal file
View File

@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const Pool_1 = require("./Pool");
exports.Pool = Pool_1.Pool;
const TimeoutError_1 = require("./TimeoutError");
exports.TimeoutError = TimeoutError_1.TimeoutError;
module.exports = {
Pool: Pool_1.Pool,
TimeoutError: TimeoutError_1.TimeoutError
};

14
backend/apis/nodejs/node_modules/tarn/dist/utils.d.ts generated vendored Normal file
View File

@ -0,0 +1,14 @@
import { PromiseInspection } from './PromiseInspection';
export interface Deferred<T> {
resolve: (val: T) => any;
reject: <T>(err: T) => any;
promise: Promise<T>;
}
export declare function defer<T>(): Deferred<T>;
export declare function now(): number;
export declare function duration(t1: number, t2: number): number;
export declare function checkOptionalTime(time?: number): boolean;
export declare function checkRequiredTime(time: number): boolean;
export declare function delay(millis: number): Promise<unknown>;
export declare function reflect<T>(promise: Promise<T>): Promise<PromiseInspection<T> | PromiseInspection<unknown>>;
export declare function tryPromise<T>(cb: () => T | PromiseLike<T>): Promise<T>;

60
backend/apis/nodejs/node_modules/tarn/dist/utils.js generated vendored Normal file
View File

@ -0,0 +1,60 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const PromiseInspection_1 = require("./PromiseInspection");
function defer() {
let resolve = null;
let reject = null;
const promise = new Promise((resolver, rejecter) => {
resolve = resolver;
reject = rejecter;
});
return {
promise,
resolve,
reject
};
}
exports.defer = defer;
function now() {
return Date.now();
}
exports.now = now;
function duration(t1, t2) {
return Math.abs(t2 - t1);
}
exports.duration = duration;
function checkOptionalTime(time) {
if (typeof time === 'undefined') {
return true;
}
return checkRequiredTime(time);
}
exports.checkOptionalTime = checkOptionalTime;
function checkRequiredTime(time) {
return typeof time === 'number' && time === Math.round(time) && time > 0;
}
exports.checkRequiredTime = checkRequiredTime;
function delay(millis) {
return new Promise(resolve => setTimeout(resolve, millis));
}
exports.delay = delay;
function reflect(promise) {
return promise
.then(value => {
return new PromiseInspection_1.PromiseInspection({ value });
})
.catch(error => {
return new PromiseInspection_1.PromiseInspection({ error });
});
}
exports.reflect = reflect;
function tryPromise(cb) {
try {
const result = cb();
return Promise.resolve(result);
}
catch (err) {
return Promise.reject(err);
}
}
exports.tryPromise = tryPromise;

66
backend/apis/nodejs/node_modules/tarn/package.json generated vendored Normal file
View File

@ -0,0 +1,66 @@
{
"name": "tarn",
"version": "3.0.2",
"description": "Simple and robust resource pool for node.js",
"main": "dist/tarn.js",
"types": "dist/tarn.d.ts",
"license": "MIT",
"scripts": {
"test": "mocha --slow 10 --timeout 5000 --reporter spec tests.js",
"test-bail": "mocha --slow 10 --timeout 5000 --reporter spec --bail tests.js",
"build": "tsc",
"clean": "rm -rf dist",
"prepublishOnly": "tsc",
"lint": "eslint --format codeframe \"src/**/*.ts\"",
"format": "prettier **/*.{js,ts} --write"
},
"author": {
"name": "Sami Koskimäki",
"email": "sami.koskimaki@vincit.com",
"url": "https://github.com/koskimas"
},
"repository": {
"type": "git",
"url": "git://github.com/vincit/tarn.js.git"
},
"engines": {
"node": ">=8.0.0"
},
"keywords": [
"pool",
"pooling",
"throttle"
],
"files": [
"README.md",
"LICENSE",
"dist/*"
],
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{js,ts}": [
"prettier --write",
"git add"
]
},
"devDependencies": {
"@types/node": "^10.17.17",
"@typescript-eslint/eslint-plugin": "^2.21.0",
"@typescript-eslint/parser": "^2.21.0",
"bluebird": "^3.7.2",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.0",
"eslint-plugin-prettier": "^3.1.2",
"expect.js": "^0.3.1",
"husky": "^1.3.1",
"lint-staged": "^9.5.0",
"mocha": "^7.1.0",
"prettier": "^1.19.1",
"typescript": "3.8.3"
},
"dependencies": {}
}