@autofleet/matmon 2.0.8 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/lib/cache.d.ts +0 -8
- package/lib/cache.js +0 -79
- package/lib/index.d.ts +0 -4
- package/lib/index.js +0 -14
- package/lib/locking.d.ts +0 -3
- package/lib/locking.js +0 -17
- package/lib/logger.d.ts +0 -2
- package/lib/logger.js +0 -5
- package/lib/orm-cache/adapter.d.ts +0 -17
- package/lib/orm-cache/adapter.js +0 -2
- package/lib/orm-cache/errors.d.ts +0 -2
- package/lib/orm-cache/errors.js +0 -6
- package/lib/orm-cache/index.d.ts +0 -12
- package/lib/orm-cache/index.js +0 -38
- package/lib/orm-cache/sequelize-adapter.d.ts +0 -13
- package/lib/orm-cache/sequelize-adapter.js +0 -156
- package/lib/redis/errors.d.ts +0 -13
- package/lib/redis/errors.js +0 -25
- package/lib/redis/index.d.ts +0 -18
- package/lib/redis/index.js +0 -107
package/package.json
CHANGED
package/lib/cache.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export declare const getNewLRU: (lifeTimeInSec: any, size: any) => any;
|
|
2
|
-
export declare const getWithCacheSupport: ({ cacheKey, cacheGet, cacheSet, fetching, skipCache, }: {
|
|
3
|
-
cacheKey: any;
|
|
4
|
-
cacheGet: any;
|
|
5
|
-
cacheSet: any;
|
|
6
|
-
fetching: any;
|
|
7
|
-
skipCache: any;
|
|
8
|
-
}) => Promise<any>;
|
package/lib/cache.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
-
}) : (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
o[k2] = m[k];
|
|
8
|
-
}));
|
|
9
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
-
}) : function(o, v) {
|
|
12
|
-
o["default"] = v;
|
|
13
|
-
});
|
|
14
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
-
if (mod && mod.__esModule) return mod;
|
|
16
|
-
var result = {};
|
|
17
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
-
__setModuleDefault(result, mod);
|
|
19
|
-
return result;
|
|
20
|
-
};
|
|
21
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
22
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
|
-
};
|
|
24
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.getWithCacheSupport = exports.getNewLRU = void 0;
|
|
26
|
-
const lru_cache_1 = __importDefault(require("lru-cache"));
|
|
27
|
-
const locking = __importStar(require("./locking"));
|
|
28
|
-
const dotenv_1 = __importDefault(require("dotenv"));
|
|
29
|
-
dotenv_1.default.config();
|
|
30
|
-
const DEFAULT_CACHE_SIZE = 300;
|
|
31
|
-
const MAX_SIZE = 100000;
|
|
32
|
-
const MUTEX_MAP = {};
|
|
33
|
-
const getOptions = ({ lifeTimeInSec, size = DEFAULT_CACHE_SIZE, }) => ({
|
|
34
|
-
max: Math.min(size, MAX_SIZE),
|
|
35
|
-
maxAge: process.env.NODE_ENV !== 'test' ? 1000 * lifeTimeInSec : 0,
|
|
36
|
-
});
|
|
37
|
-
const getMutexByCacheKey = (key) => {
|
|
38
|
-
if (!MUTEX_MAP[key]) {
|
|
39
|
-
MUTEX_MAP[key] = locking.getMutex();
|
|
40
|
-
}
|
|
41
|
-
return MUTEX_MAP[key];
|
|
42
|
-
};
|
|
43
|
-
const deleteMutexByCacheKey = (key) => {
|
|
44
|
-
if (MUTEX_MAP[key]) {
|
|
45
|
-
delete MUTEX_MAP[key];
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
exports.getNewLRU = (lifeTimeInSec, size) => new lru_cache_1.default(getOptions({
|
|
49
|
-
lifeTimeInSec,
|
|
50
|
-
size,
|
|
51
|
-
}));
|
|
52
|
-
exports.getWithCacheSupport = async ({ cacheKey, cacheGet, cacheSet, fetching, skipCache, }) => {
|
|
53
|
-
if (skipCache || process.env.NODE_ENV === 'test') {
|
|
54
|
-
const res = await fetching();
|
|
55
|
-
await cacheSet(res);
|
|
56
|
-
return res;
|
|
57
|
-
}
|
|
58
|
-
let valueToReturn = null;
|
|
59
|
-
try {
|
|
60
|
-
await locking.wrapWithMutex(getMutexByCacheKey(cacheKey), async () => {
|
|
61
|
-
valueToReturn = await cacheGet();
|
|
62
|
-
if (!valueToReturn) {
|
|
63
|
-
valueToReturn = await fetching();
|
|
64
|
-
await cacheSet(valueToReturn);
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
// logger.info('get value from cache');
|
|
68
|
-
}
|
|
69
|
-
deleteMutexByCacheKey(cacheKey);
|
|
70
|
-
});
|
|
71
|
-
// retry without locking if failed
|
|
72
|
-
}
|
|
73
|
-
catch (e) {
|
|
74
|
-
valueToReturn = await fetching();
|
|
75
|
-
await cacheSet(valueToReturn);
|
|
76
|
-
deleteMutexByCacheKey(cacheKey);
|
|
77
|
-
}
|
|
78
|
-
return valueToReturn;
|
|
79
|
-
};
|
package/lib/index.d.ts
DELETED
package/lib/index.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ORMTypes = exports.ORMCache = exports.RedisCache = exports.getWithCacheSupport = exports.getNewLRU = void 0;
|
|
7
|
-
const cache_1 = require("./cache");
|
|
8
|
-
Object.defineProperty(exports, "getNewLRU", { enumerable: true, get: function () { return cache_1.getNewLRU; } });
|
|
9
|
-
Object.defineProperty(exports, "getWithCacheSupport", { enumerable: true, get: function () { return cache_1.getWithCacheSupport; } });
|
|
10
|
-
const redis_1 = __importDefault(require("./redis"));
|
|
11
|
-
exports.RedisCache = redis_1.default;
|
|
12
|
-
const orm_cache_1 = require("./orm-cache");
|
|
13
|
-
Object.defineProperty(exports, "ORMCache", { enumerable: true, get: function () { return orm_cache_1.ORMCache; } });
|
|
14
|
-
Object.defineProperty(exports, "ORMTypes", { enumerable: true, get: function () { return orm_cache_1.ORMTypes; } });
|
package/lib/locking.d.ts
DELETED
package/lib/locking.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getMutex = exports.wrapWithMutex = void 0;
|
|
4
|
-
const async_mutex_1 = require("async-mutex");
|
|
5
|
-
const CACHE_LOCK_TIMEOUT_MILIS = 3000;
|
|
6
|
-
const LOCK_TIMEOUT_MESSAGE = 'mutex - locking timeout';
|
|
7
|
-
// eslint-disable-next-line import/prefer-default-export
|
|
8
|
-
exports.wrapWithMutex = async (mutex, funcToRun) => {
|
|
9
|
-
const release = await mutex.acquire();
|
|
10
|
-
try {
|
|
11
|
-
await funcToRun();
|
|
12
|
-
}
|
|
13
|
-
finally {
|
|
14
|
-
release();
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
exports.getMutex = () => async_mutex_1.withTimeout(new async_mutex_1.Mutex(), CACHE_LOCK_TIMEOUT_MILIS, new Error(LOCK_TIMEOUT_MESSAGE));
|
package/lib/logger.d.ts
DELETED
package/lib/logger.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import RedisCache from '../redis';
|
|
2
|
-
export interface ModelOptions {
|
|
3
|
-
name: string;
|
|
4
|
-
associations?: AssociationOptions[];
|
|
5
|
-
}
|
|
6
|
-
export interface AssociationOptions {
|
|
7
|
-
name: string;
|
|
8
|
-
alias: string;
|
|
9
|
-
accessKey?: string;
|
|
10
|
-
innerAssociation?: AssociationOptions;
|
|
11
|
-
}
|
|
12
|
-
export interface Adapter {
|
|
13
|
-
ormInstance: any;
|
|
14
|
-
getModel: (modelName: string) => any;
|
|
15
|
-
injectGetWithCacheFunction: (cache: RedisCache, modelOptions: ModelOptions) => void;
|
|
16
|
-
addInvalidationHooks: (cache: RedisCache, modelOptions: ModelOptions) => void;
|
|
17
|
-
}
|
package/lib/orm-cache/adapter.js
DELETED
package/lib/orm-cache/errors.js
DELETED
package/lib/orm-cache/index.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { ModelOptions } from './adapter';
|
|
2
|
-
export declare enum ORMTypes {
|
|
3
|
-
SEQUELIZE = "sequelize"
|
|
4
|
-
}
|
|
5
|
-
interface ORMCacheOptions {
|
|
6
|
-
type: ORMTypes;
|
|
7
|
-
models: ModelOptions[];
|
|
8
|
-
ormInstance: any;
|
|
9
|
-
debug: boolean;
|
|
10
|
-
}
|
|
11
|
-
export declare const ORMCache: (options: ORMCacheOptions) => void;
|
|
12
|
-
export {};
|
package/lib/orm-cache/index.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ORMCache = exports.ORMTypes = void 0;
|
|
7
|
-
const sequelize_adapter_1 = __importDefault(require("./sequelize-adapter"));
|
|
8
|
-
const errors_1 = require("./errors");
|
|
9
|
-
const redis_1 = __importDefault(require("../redis"));
|
|
10
|
-
const logger_1 = __importDefault(require("../logger"));
|
|
11
|
-
var ORMTypes;
|
|
12
|
-
(function (ORMTypes) {
|
|
13
|
-
ORMTypes["SEQUELIZE"] = "sequelize";
|
|
14
|
-
})(ORMTypes = exports.ORMTypes || (exports.ORMTypes = {}));
|
|
15
|
-
const ORMInstanceFactory = (options) => {
|
|
16
|
-
switch (options.type) {
|
|
17
|
-
case ORMTypes.SEQUELIZE: {
|
|
18
|
-
return new sequelize_adapter_1.default(options.ormInstance, options.debug);
|
|
19
|
-
}
|
|
20
|
-
default: {
|
|
21
|
-
throw new errors_1.UnsupportedOrmTypeError(`ORM type ${options.type} is unsupported at the moment`);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
exports.ORMCache = (options) => {
|
|
26
|
-
const { models } = options;
|
|
27
|
-
logger_1.default.info('Starting ORM Cache', { options });
|
|
28
|
-
const adapter = ORMInstanceFactory(options);
|
|
29
|
-
const cache = new redis_1.default({
|
|
30
|
-
host: process.env.REDIS_HOST,
|
|
31
|
-
port: process.env.REDIS_PORT,
|
|
32
|
-
});
|
|
33
|
-
// eslint-disable-next-line array-callback-return
|
|
34
|
-
models.map((modelOptions) => {
|
|
35
|
-
adapter.addInvalidationHooks(cache, modelOptions);
|
|
36
|
-
adapter.injectGetWithCacheFunction(cache, modelOptions);
|
|
37
|
-
});
|
|
38
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Sequelize } from 'sequelize';
|
|
2
|
-
import { Adapter, AssociationOptions, ModelOptions } from './adapter';
|
|
3
|
-
import RedisCache from '../redis';
|
|
4
|
-
export default class SequelizeAdapter implements Adapter {
|
|
5
|
-
ormInstance: Sequelize;
|
|
6
|
-
debugMode: boolean;
|
|
7
|
-
constructor(sequelize: Sequelize, debug: any);
|
|
8
|
-
getModel(modelName: string): any;
|
|
9
|
-
getModelDependencies(modelName: string): AssociationOptions[];
|
|
10
|
-
debug(message: any, payload: any): void;
|
|
11
|
-
injectGetWithCacheFunction(cache: RedisCache, modelOptions: ModelOptions): void;
|
|
12
|
-
addInvalidationHooks(cache: RedisCache, modelOptions: ModelOptions): void;
|
|
13
|
-
}
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const logger_1 = __importDefault(require("../logger"));
|
|
7
|
-
const util_1 = require("util");
|
|
8
|
-
const { AF_SERVICE_NAME } = process.env;
|
|
9
|
-
const ORM_CACHE_PREFIX = 'ormCache';
|
|
10
|
-
const INVALIDATION_HOOKS = ['afterSave', 'afterUpdate', 'afterDestroy'];
|
|
11
|
-
const BULK_HOOKS = ['beforeBulkUpdate', 'beforeBulkDestroy'];
|
|
12
|
-
const generateInstanceKey = (name, id) => `${AF_SERVICE_NAME}:${ORM_CACHE_PREFIX}:${name}_${id}`;
|
|
13
|
-
const generateDependencyKey = (modelName, associationName, associationId) => `${AF_SERVICE_NAME}:${ORM_CACHE_PREFIX}:${modelName}_${associationName}_${associationId}_DEPENDENCIES`;
|
|
14
|
-
const getInstanceDependencyKeys = (modelOptions, instance) => {
|
|
15
|
-
const keys = modelOptions.associations
|
|
16
|
-
.filter((associationOptions) => instance[associationOptions.alias])
|
|
17
|
-
.map((associationOptions) => {
|
|
18
|
-
const accessKey = associationOptions.accessKey;
|
|
19
|
-
const depKeys = [];
|
|
20
|
-
if (Array.isArray(instance[associationOptions.alias])) {
|
|
21
|
-
instance[associationOptions.alias].map(associationInstance => {
|
|
22
|
-
depKeys.push(generateDependencyKey(modelOptions.name, associationOptions.name, associationInstance[accessKey]));
|
|
23
|
-
if (associationOptions.innerAssociation &&
|
|
24
|
-
associationInstance[associationOptions.innerAssociation.alias]) {
|
|
25
|
-
depKeys.push(generateDependencyKey(modelOptions.name, associationOptions.innerAssociation.name, associationInstance[associationOptions.innerAssociation.alias][associationOptions.innerAssociation.accessKey]));
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
return depKeys;
|
|
29
|
-
}
|
|
30
|
-
return [
|
|
31
|
-
generateDependencyKey(modelOptions.name, associationOptions.name, instance[associationOptions.alias][accessKey]),
|
|
32
|
-
];
|
|
33
|
-
});
|
|
34
|
-
return keys.reduce((flattenArray, array) => flattenArray.concat(array), []);
|
|
35
|
-
};
|
|
36
|
-
const handleTransactionHook = (instance, options, func) => {
|
|
37
|
-
const { transaction } = options;
|
|
38
|
-
if (transaction) {
|
|
39
|
-
transaction.afterCommit(() => func(instance));
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
func(instance);
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
class SequelizeAdapter {
|
|
46
|
-
constructor(sequelize, debug) {
|
|
47
|
-
this.ormInstance = sequelize;
|
|
48
|
-
this.debugMode = debug;
|
|
49
|
-
}
|
|
50
|
-
getModel(modelName) {
|
|
51
|
-
return this.ormInstance.models[modelName];
|
|
52
|
-
}
|
|
53
|
-
getModelDependencies(modelName) {
|
|
54
|
-
const { associations } = this.ormInstance.models[modelName];
|
|
55
|
-
return [
|
|
56
|
-
...Object.keys(associations).map(association => {
|
|
57
|
-
const sequelizeAssociation = associations[association];
|
|
58
|
-
const associationOptions = {
|
|
59
|
-
alias: sequelizeAssociation.as,
|
|
60
|
-
name: sequelizeAssociation.target.name,
|
|
61
|
-
accessKey: sequelizeAssociation.target.primaryKeyAttribute,
|
|
62
|
-
};
|
|
63
|
-
if (sequelizeAssociation.through) {
|
|
64
|
-
const relationModel = sequelizeAssociation.through.model;
|
|
65
|
-
associationOptions.innerAssociation = {
|
|
66
|
-
alias: relationModel.name,
|
|
67
|
-
name: relationModel.name,
|
|
68
|
-
accessKey: relationModel.primaryKeyAttribute,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
return associationOptions;
|
|
72
|
-
}),
|
|
73
|
-
];
|
|
74
|
-
}
|
|
75
|
-
debug(message, payload) {
|
|
76
|
-
if (this.debugMode) {
|
|
77
|
-
logger_1.default.info(`[ORM_CACHE Debug] ${message}`, payload);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
injectGetWithCacheFunction(cache, modelOptions) {
|
|
81
|
-
const addDependencies = async (instance) => {
|
|
82
|
-
const dependencyKeys = getInstanceDependencyKeys(modelOptions, instance);
|
|
83
|
-
const instanceKey = generateInstanceKey(modelOptions.name, instance.id);
|
|
84
|
-
this.debug('Adding dependencies', { instanceKey, dependencyKeys });
|
|
85
|
-
const addDependenciesMulti = cache.getClient().multi();
|
|
86
|
-
const addDependenciesMultiAsync = util_1.promisify(addDependenciesMulti.exec).bind(addDependenciesMulti);
|
|
87
|
-
dependencyKeys.reduce((multi, key) => multi.sadd(key, instanceKey), addDependenciesMulti);
|
|
88
|
-
return addDependenciesMultiAsync();
|
|
89
|
-
};
|
|
90
|
-
const model = this.getModel(modelOptions.name);
|
|
91
|
-
model.findByPkCached = async (id, scopes, options) => {
|
|
92
|
-
const cacheKey = generateInstanceKey(modelOptions.name, id);
|
|
93
|
-
let value = JSON.parse(await cache.getClient().getAsync(cacheKey));
|
|
94
|
-
if (!value) {
|
|
95
|
-
this.debug('Value not found in cache, looking in db', { id, cacheKey });
|
|
96
|
-
value = await model.scope(scopes).findByPk(id, options);
|
|
97
|
-
this.debug('Value from DB', { value: value || 'not found', cacheKey });
|
|
98
|
-
await Promise.all([
|
|
99
|
-
cache.getClient().setAsync(cacheKey, JSON.stringify(value)),
|
|
100
|
-
value && addDependencies(value),
|
|
101
|
-
]);
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
value = this.getModel(modelOptions.name).build(value, { isNewRecord: false, include: options.include });
|
|
105
|
-
this.debug('Found cached value', { value, id, cacheKey });
|
|
106
|
-
}
|
|
107
|
-
return value;
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
addInvalidationHooks(cache, modelOptions) {
|
|
111
|
-
const invalidateModelInstance = async (instance) => {
|
|
112
|
-
const dependencyKeys = getInstanceDependencyKeys(modelOptions, instance);
|
|
113
|
-
const instanceKey = generateInstanceKey(modelOptions.name, instance.id);
|
|
114
|
-
this.debug('Removing dependencies', { instance, instanceKey, dependencyKeys });
|
|
115
|
-
const removeMulti = cache.getClient().multi();
|
|
116
|
-
const removeMultiAsync = util_1.promisify(removeMulti.exec).bind(removeMulti);
|
|
117
|
-
dependencyKeys.map(key => removeMulti.srem(key, instanceKey));
|
|
118
|
-
removeMulti.del(instanceKey);
|
|
119
|
-
return removeMultiAsync();
|
|
120
|
-
};
|
|
121
|
-
const invalidateModelInstanceByAssociation = async (association, associationId) => {
|
|
122
|
-
const dependentInstancesKeys = await cache.getClient().smembersAsync(generateDependencyKey(modelOptions.name, association, associationId));
|
|
123
|
-
this.debug('Invalidating dependent instances', { dependentInstancesKeys });
|
|
124
|
-
const removeMulti = cache.getClient().multi();
|
|
125
|
-
const removeMultiAsync = util_1.promisify(removeMulti.exec).bind(removeMulti);
|
|
126
|
-
const dependenciesToRemove = await Promise.all(dependentInstancesKeys.map(async (instanceKey) => {
|
|
127
|
-
const instance = JSON.parse(await cache.getClient().getAsync(instanceKey));
|
|
128
|
-
if (!instance) {
|
|
129
|
-
return [];
|
|
130
|
-
}
|
|
131
|
-
const dependencyKeys = getInstanceDependencyKeys(modelOptions, instance);
|
|
132
|
-
dependencyKeys.reduce((multi, key) => multi.srem(key, instanceKey), removeMulti);
|
|
133
|
-
removeMulti.del(instanceKey);
|
|
134
|
-
return dependencyKeys;
|
|
135
|
-
}));
|
|
136
|
-
this.debug('Removing dependencies', { dependentInstancesKeys, dependenciesToRemove });
|
|
137
|
-
return removeMultiAsync();
|
|
138
|
-
};
|
|
139
|
-
const model = this.getModel(modelOptions.name);
|
|
140
|
-
INVALIDATION_HOOKS.map(hook => model.addHook(hook, (instance, options) => handleTransactionHook(instance, options, instance => invalidateModelInstance(instance))));
|
|
141
|
-
BULK_HOOKS.map(hook => model.addHook(hook, options => options.individualHook = true));
|
|
142
|
-
modelOptions.associations = this.getModelDependencies(modelOptions.name);
|
|
143
|
-
this.debug(`Adding Invalidations Hooks to ${modelOptions.name}'s associations`, { associations: modelOptions.associations });
|
|
144
|
-
modelOptions.associations.map((associationOptions) => {
|
|
145
|
-
const associationModel = this.getModel(associationOptions.name);
|
|
146
|
-
INVALIDATION_HOOKS.map(hook => associationModel.addHook(hook, (instance, options) => handleTransactionHook(instance, options, associationInstance => invalidateModelInstanceByAssociation(associationOptions.name, associationInstance[associationOptions.accessKey]))));
|
|
147
|
-
BULK_HOOKS.map(hook => associationModel.addHook(hook, options => options.individualHook = true));
|
|
148
|
-
if (associationOptions.innerAssociation) {
|
|
149
|
-
const innerAssociationModel = this.getModel(associationOptions.innerAssociation.name);
|
|
150
|
-
INVALIDATION_HOOKS.map(hook => innerAssociationModel.addHook(hook, (instance, options) => handleTransactionHook(instance, options, innerAssociationInstance => invalidateModelInstanceByAssociation(associationOptions.innerAssociation.name, innerAssociationInstance[associationOptions.innerAssociation.accessKey]))));
|
|
151
|
-
BULK_HOOKS.map(hook => innerAssociationModel.addHook(hook, options => options.individualHook = true));
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
exports.default = SequelizeAdapter;
|
package/lib/redis/errors.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { RedisError } from 'redis';
|
|
2
|
-
declare class RedisCacheError extends RedisError {
|
|
3
|
-
innerError: any;
|
|
4
|
-
message: string;
|
|
5
|
-
constructor(msg: string, err: any);
|
|
6
|
-
toString(): string;
|
|
7
|
-
}
|
|
8
|
-
declare class RedisLockError extends RedisCacheError {
|
|
9
|
-
key: string;
|
|
10
|
-
constructor(msg: string, err: any, key: string);
|
|
11
|
-
toString(): string;
|
|
12
|
-
}
|
|
13
|
-
export { RedisCacheError, RedisLockError, };
|
package/lib/redis/errors.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RedisLockError = exports.RedisCacheError = void 0;
|
|
4
|
-
const redis_1 = require("redis");
|
|
5
|
-
class RedisCacheError extends redis_1.RedisError {
|
|
6
|
-
constructor(msg, err) {
|
|
7
|
-
super();
|
|
8
|
-
this.innerError = err;
|
|
9
|
-
this.message = msg;
|
|
10
|
-
}
|
|
11
|
-
toString() {
|
|
12
|
-
return `${this.message}: ${this.innerError}`;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
exports.RedisCacheError = RedisCacheError;
|
|
16
|
-
class RedisLockError extends RedisCacheError {
|
|
17
|
-
constructor(msg, err, key) {
|
|
18
|
-
super(msg, err);
|
|
19
|
-
this.key = key;
|
|
20
|
-
}
|
|
21
|
-
toString() {
|
|
22
|
-
return `${this.message} (${this.key}): ${this.innerError}`;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
exports.RedisLockError = RedisLockError;
|
package/lib/redis/index.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
declare class RedisCache {
|
|
2
|
-
private client;
|
|
3
|
-
private locker;
|
|
4
|
-
private lockTimeout;
|
|
5
|
-
private lockDuration;
|
|
6
|
-
private locks;
|
|
7
|
-
private baseTTL;
|
|
8
|
-
private lockRetries;
|
|
9
|
-
private useLock;
|
|
10
|
-
constructor(options: any);
|
|
11
|
-
get(key: any): Promise<any>;
|
|
12
|
-
set(key: any, value: any): Promise<void>;
|
|
13
|
-
remove(key: any): Promise<void>;
|
|
14
|
-
removeMultiple(keys: any): Promise<void>;
|
|
15
|
-
getClient(): any;
|
|
16
|
-
private lock;
|
|
17
|
-
}
|
|
18
|
-
export default RedisCache;
|
package/lib/redis/index.js
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const redis_1 = __importDefault(require("redis"));
|
|
7
|
-
const redis_lock_1 = __importDefault(require("redis-lock"));
|
|
8
|
-
const bluebird_1 = __importDefault(require("bluebird"));
|
|
9
|
-
const util_1 = require("util");
|
|
10
|
-
const errors_1 = require("./errors");
|
|
11
|
-
bluebird_1.default.promisifyAll(redis_1.default.RedisClient.prototype);
|
|
12
|
-
bluebird_1.default.promisifyAll(redis_1.default.Multi.prototype);
|
|
13
|
-
const { env } = process;
|
|
14
|
-
const HOST = env.REDIS_HOST_NAME || '127.0.0.1';
|
|
15
|
-
const PORT = env.REDIS_HOST_PORT || 6379;
|
|
16
|
-
const SERVICE_NAME = env.AF_SERVICE_NAME;
|
|
17
|
-
const DEFAULT_LOCK_TIMEOUT = 5000;
|
|
18
|
-
const DEFAULT_LOCK_DURATION = 1000;
|
|
19
|
-
const DEFAULT_BASE_TTL = 3600;
|
|
20
|
-
const KEY_PREFIX = SERVICE_NAME + ':';
|
|
21
|
-
if (!SERVICE_NAME) {
|
|
22
|
-
throw new Error('SERVICE_NAME cannot be null, please check your env.AF_SERVICE_NAME');
|
|
23
|
-
}
|
|
24
|
-
class RedisCache {
|
|
25
|
-
constructor(options) {
|
|
26
|
-
this.client = redis_1.default.createClient({
|
|
27
|
-
host: options.host || HOST,
|
|
28
|
-
port: options.port || PORT,
|
|
29
|
-
});
|
|
30
|
-
this.locker = util_1.promisify(redis_lock_1.default(this.client, options.lockRetries ?? 10));
|
|
31
|
-
this.lockTimeout = options.lockTimeout ?? DEFAULT_LOCK_TIMEOUT;
|
|
32
|
-
this.lockDuration = options.lockDuration ?? DEFAULT_LOCK_DURATION;
|
|
33
|
-
this.baseTTL = options.ttl ?? DEFAULT_BASE_TTL;
|
|
34
|
-
this.locks = {};
|
|
35
|
-
this.useLock = !!options.useLock;
|
|
36
|
-
}
|
|
37
|
-
async get(key) {
|
|
38
|
-
const keyWithPrefix = KEY_PREFIX + key;
|
|
39
|
-
let value;
|
|
40
|
-
try {
|
|
41
|
-
// Try to get the value from redis.
|
|
42
|
-
value = await this.client.getAsync(keyWithPrefix);
|
|
43
|
-
}
|
|
44
|
-
catch (err) {
|
|
45
|
-
throw new errors_1.RedisCacheError('Failed to get a value', err);
|
|
46
|
-
}
|
|
47
|
-
if (this.useLock) {
|
|
48
|
-
let lock;
|
|
49
|
-
try {
|
|
50
|
-
// Try to lock the key.
|
|
51
|
-
lock = await this.lock(keyWithPrefix);
|
|
52
|
-
}
|
|
53
|
-
catch (err) {
|
|
54
|
-
throw new errors_1.RedisLockError('Failed to lock key', err, keyWithPrefix);
|
|
55
|
-
}
|
|
56
|
-
// If the lock did not fail, add it to a locks dictionary.
|
|
57
|
-
this.locks[keyWithPrefix] = lock;
|
|
58
|
-
}
|
|
59
|
-
return JSON.parse(value);
|
|
60
|
-
}
|
|
61
|
-
async set(key, value) {
|
|
62
|
-
const keyWithPrefix = KEY_PREFIX + key;
|
|
63
|
-
const ttl = parseInt(String(this.baseTTL * (Math.random() + 1)), 10);
|
|
64
|
-
try {
|
|
65
|
-
await this.client.setAsync(keyWithPrefix, JSON.stringify(value), 'EX', ttl);
|
|
66
|
-
if (this.locks[keyWithPrefix]) {
|
|
67
|
-
await this.locks[keyWithPrefix]();
|
|
68
|
-
delete this.locks[keyWithPrefix];
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
catch (err) {
|
|
72
|
-
throw new errors_1.RedisCacheError('Failed to set a key-value pair', err);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
async remove(key) {
|
|
76
|
-
const keyWithPrefix = KEY_PREFIX + key;
|
|
77
|
-
try {
|
|
78
|
-
if (this.locks[keyWithPrefix]) {
|
|
79
|
-
await this.locks[keyWithPrefix]();
|
|
80
|
-
delete this.locks[keyWithPrefix];
|
|
81
|
-
}
|
|
82
|
-
await this.client.delAsync(keyWithPrefix);
|
|
83
|
-
}
|
|
84
|
-
catch (err) {
|
|
85
|
-
throw new errors_1.RedisCacheError(`Failed to delete key ${keyWithPrefix}`, err);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
async removeMultiple(keys) {
|
|
89
|
-
const keysWithPrefix = keys.map(key => KEY_PREFIX + key);
|
|
90
|
-
try {
|
|
91
|
-
await this.client.delAsync(keysWithPrefix);
|
|
92
|
-
}
|
|
93
|
-
catch (err) {
|
|
94
|
-
throw new errors_1.RedisCacheError(`Failed to delete multiple keys ${keysWithPrefix.join('|')}`, err);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
getClient() {
|
|
98
|
-
return this.client;
|
|
99
|
-
}
|
|
100
|
-
lock(key) {
|
|
101
|
-
return Promise.race([
|
|
102
|
-
this.locker(key, this.lockDuration),
|
|
103
|
-
new Promise((resolve, reject) => setTimeout(() => reject(), this.lockTimeout)),
|
|
104
|
-
]);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
exports.default = RedisCache;
|