Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

contextor

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

contextor - npm Package Compare versions

Comparing version 0.5.0 to 0.6.0

122

index.js
'use strict';
const asyncHooks = require('async_hooks');
const v8 = require('v8');
const vm = require('vm');
let gc = global.gc;
if (!gc) {
v8.setFlagsFromString('--expose_gc');
gc = vm.runInNewContext('gc');
}
// Module global variables.
const resourceTree = {};
const contexts = {};
const contextAges = {};
const childResources = {};

@@ -21,3 +13,49 @@ const parentResources = {};

let createdContextNumberSinceLastCleanCheck = 0;
const CLEAN_CHECK_CONTEXT_SIZE = process.env.CONTEXTOR_CLEAN_CHECK_CONTEXT_SIZE || 100;
const CONTEXT_TTL = process.env.CONTEXTOR_CONTEXT_TTL || 6e4;
/**
* Retrieve context id for an async resource.
* @param {number} asyncId - The resource id.
* @returns {number|undefined} The context id or undefined if not in a context.
*/
function retrieveContextId(asyncId) {
let contextId = asyncId;
while (contextId !== undefined && !(contextId in contexts)) {
contextId = resourceTree[contextId];
}
return contextId;
}
/**
* Retrieve current context id.
* @returns {number|undefined} The current context id or undefined if not in a context.
*/
function retrieveCurrentContextId() {
return retrieveContextId(asyncHooks.executionAsyncId());
}
/**
* Retrieve current context.
* @returns {Object} The current context.
* @throws {ReferenceError} On missing current context.
*/
function retrieveCurrentContext() {
const asyncId = retrieveCurrentContextId();
const exists = asyncId in contexts;
if (!exists) {
throw new ReferenceError(
'No current context found; use \'create\' method to create one'
);
}
return contexts[asyncId];
}
/**
* Async hook init callback.

@@ -29,6 +67,2 @@ * - build resource tree allowing to resolve current context

function init(asyncId, type, triggerAsyncId) {
if (!triggerAsyncId) {
return;
}
resourceTree[asyncId] = triggerAsyncId;

@@ -57,3 +91,3 @@

// Clean memory.
// Clean memory references.
const resources = [asyncId].concat(parentResources[asyncId]);

@@ -78,6 +112,8 @@

const destroyed = parentAsyncId in destroyedResources;
const hasContext = !!retrieveContextId(parentAsyncId);
if (!hasChildren && destroyed) {
if ((!hasChildren && destroyed) || !hasContext) {
delete resourceTree[parentAsyncId];
delete contexts[parentAsyncId];
delete contextAges[parentAsyncId];
delete childResources[parentAsyncId];

@@ -98,38 +134,26 @@ delete parentResources[parentAsyncId];

/**
* Retrieve current context id.
* @returns {number|undefined} The current context id.
* Clean deprecated and useless resources.
*/
function retrieveCurrentContextId() {
let asyncId = asyncHooks.executionAsyncId();
function cleanResources() {
const now = Date.now();
while (asyncId !== undefined && !(asyncId in contexts)) {
asyncId = resourceTree[asyncId];
// Clean expired contexts (in case a destroy has not been fired).
if (CONTEXT_TTL) {
Object.getOwnPropertyNames(contexts).forEach((asyncId) => {
if (now - contextAges[asyncId] >= CONTEXT_TTL) {
delete contexts[asyncId];
delete contextAges[asyncId];
}
});
}
return asyncId;
// Clean resources not attached to a context.
Object.getOwnPropertyNames(resourceTree).forEach((asyncId) => {
if (!retrieveContextId(asyncId)) {
destroy(asyncId);
}
});
}
/**
* Retrieve current context.
* @returns {Object} The current context.
* @throws {ReferenceError} On missing current context.
*/
function retrieveCurrentContext() {
const asyncId = retrieveCurrentContextId();
const exists = asyncId in contexts;
if (!exists) {
throw new ReferenceError(
'No current context found; use \'create\' method to create one'
);
}
return contexts[asyncId];
}
let createdContextNumberSinceLastCleanCheck = 0;
const CLEAN_CHECK_CONTEXT_SIZE = process.env.CONTEXTOR_CLEAN_CHECK_CONTEXT_SIZE || 100;
const DESTROY_STACK_SIZE = process.env.CONTEXTOR_DESTROY_STACK_SIZE || 1000;
/**
* Create a new context.

@@ -141,11 +165,7 @@ * @returns {self}

contexts[asyncId] = {};
contextAges[asyncId] = Date.now();
// Call manual garbage collector execution on garbage stacking.
if (createdContextNumberSinceLastCleanCheck >= CLEAN_CHECK_CONTEXT_SIZE) {
if (Object.getOwnPropertyNames(destroyedResources).length >= DESTROY_STACK_SIZE) {
gc();
}
if (++createdContextNumberSinceLastCleanCheck >= CLEAN_CHECK_CONTEXT_SIZE) {
cleanResources();
createdContextNumberSinceLastCleanCheck = 0;
} else {
createdContextNumberSinceLastCleanCheck++;
}

@@ -152,0 +172,0 @@

{
"name": "contextor",
"description": "Package allowing to pass a context along an asynchronous process",
"version": "0.5.0",
"version": "0.6.0",
"author": "Thomas Prelot <tprelot@gmail.com> (https://github.com/Gnucki)",

@@ -28,7 +28,7 @@ "contributors": [],

"lint-fix": "gnodi-lint --fix",
"test": "NODE_ENV='test' mocha --recursive index.js test.js",
"test": "NODE_ENV=test CONTEXTOR_CLEAN_CHECK_CONTEXT_SIZE=2 CONTEXTOR_CONTEXT_TTL=200 mocha --recursive index.js test.js",
"test-coverage": "nyc npm test && nyc report --reporter text-summary",
"test-coveralls": "nyc npm test && nyc report --reporter text-lcov | coveralls",
"test-debug": "NODE_ENV='test' mocha --recursive --full-trace --check-leaks index.js test.js",
"test-watch": "NODE_ENV='test' mocha -w -b --recursive index.js test.js",
"test-debug": "NODE_ENV=test CONTEXTOR_CLEAN_CHECK_CONTEXT_SIZE=2 CONTEXTOR_CONTEXT_TTL=200 mocha --recursive --full-trace --check-leaks index.js test.js",
"test-watch": "NODE_ENV=test CONTEXTOR_CLEAN_CHECK_CONTEXT_SIZE=2 CONTEXTOR_CONTEXT_TTL=200 mocha -w -b --recursive index.js test.js",
"preversion": "npm run check",

@@ -35,0 +35,0 @@ "postversion": "git push && git push --tags"

@@ -65,2 +65,3 @@ # contextor

- [Get a value in the current context](#get-a-value-in-the-current-context)
- [Customize cleaning](#customize-cleaning)
- [Debugging](#debugging)

@@ -111,2 +112,7 @@ - [Testing](#testing)

### Customize cleaning
Some environment variables are available in order to customize context cleaning:
- `CONTEXTOR_CLEAN_CHECK_CONTEXT_SIZE`: number of created contexts before a cleaning is executed (default: 100)
- `CONTEXTOR_CONTEXT_TTL`: TTL of contexts in ms; set to 0 to make it infinite (default: 6e4)
### Debugging

@@ -113,0 +119,0 @@ Contextor create context for async hooks. A bad usage can lead to memory leaks.<br>

@@ -138,2 +138,34 @@ 'use strict';

});
it('should clean expired contexts', (done) => {
let memoryUsage = contextor.getMemoryUsage();
expect(memoryUsage.sizes.contexts).to.be.greaterThan(1);
setTimeout(() => {
contextor.create();
contextor.create();
memoryUsage = contextor.getMemoryUsage();
expect(memoryUsage.sizes.contexts).equal(1);
setTimeout(() => {
contextor.create();
contextor.create();
memoryUsage = contextor.getMemoryUsage();
expect(memoryUsage.sizes.contexts).equal(1);
done();
}, 400);
}, 400);
setTimeout(() => {
contextor.create();
contextor.create();
memoryUsage = contextor.getMemoryUsage();
expect(memoryUsage.sizes.contexts).equal(2);
}, 500);
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc