You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

node-execution-context

Package Overview
Dependencies
Maintainers
1
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-execution-context - npm Package Compare versions

Comparing version

to
2.0.0-beta.0

CHANGELOG.md

2

.eslintrc.js

@@ -14,3 +14,3 @@ module.exports = {

rules: {
'no-console': 0,
'no-console': 2,
'no-var': 2,

@@ -17,0 +17,0 @@ 'prefer-const': 2,

const Context = require('../src');
const delay = (callback) => setTimeout(() => {
const delay = (callback, timeout = 1000) => setTimeout(() => {
callback();
}, 2000);
}, timeout);

@@ -11,5 +11,17 @@ class UserController {

delay(() => {
console.log('Callback : ', Context.get());
console.log('Callback : ', Context.get()); // { val: true }
});
// Creates a dedicate domain context ( exclude this following chain from root context )
// Updates mae from domain will not effect root context.
delay(() => {
Context.create({ specific: true }, 'custom-domain');
delay(() => {
console.log('Domain callback ', Context.get()) // { val: true, specific: true }
Context.update({ inner: true });
}, 400);
}, 4000)
res.send(Context.get());

@@ -16,0 +28,0 @@ }

@@ -17,4 +17,4 @@ const express = require('express');

app.listen(port, function(){
app.listen(port, () => {
console.log('Server is running');
});
{
"name": "node-execution-context",
"version": "1.1.7",
"version": "2.0.0-beta.0",
"description": "Provides execution context wrapper for node JS, can be used to create execution wrapper for handling requests and more",

@@ -5,0 +5,0 @@ "author": "Oded Goldglas <odedglas@gmail.com>",

@@ -60,3 +60,3 @@ # node-execution-context

### create(initialContext?: object)
### create(initialContext?: object, domain? :string)

@@ -66,2 +66,4 @@ Creates for the current async resource an execution context entry identified with his asyncId.

> When passing custom domain to this method, the trigger point and all of it's sub processes will be exposed to a standalone context won't effect / be effected by root context.
### update(update: object)

@@ -79,2 +81,6 @@

### configure(config: ExecutionContextConfig) : void
Configures execution context settings.
### monitor(): ExecutionMapUsage

@@ -84,5 +90,18 @@

> Before calling `monitor`, you should `configure` execution context to monitor it's nodes. by default they are kept as lean as possible.
```js
const Context = require('node-execution-context');
// Startup
Context.configure({ monitor: true });
// Later on
const usage = Context.monitor();
console.log(usage); // Prints execution context usage report.
```
### API Usage
```js

@@ -118,3 +137,2 @@ const Context = require('node-execution-context');

console.log(Context.get()); // outputs: {"value": true}
console.log(Context.monitor) // Will result with monitor result
});

@@ -126,6 +144,7 @@ });

| Code | when |
| Code | When |
|-|-
| CONTEXT_ALREADY_DECLARED | When trying to `create` execution context, but current async resource already exists.
| CONTEXT_DOES_NOT_EXISTS | When try to `get` / `update` the context, but it yet been created.
| MONITOR_MISS_CONFIGURATION | When try to `monitor` without calling `configure` with monitoring option.

@@ -6,3 +6,3 @@ const { isUndefined } = require('../lib');

* Returns proper context ref for a given trigger id.
* @param {ExecutionContext} parentContext - The parent context triggered the init
* @param {ExecutionContextNode} parentContext - The parent context triggered the init
* @param {Number} triggerAsyncId - The current triggerAsyncId

@@ -29,23 +29,20 @@ */

const init = (executionContextMap) => (asyncId, type, triggerAsyncId) => {
const parentContext = executionContextMap.get(triggerAsyncId);
const parentContext = executionContextMap.get(triggerAsyncId);
if (!parentContext || EXCLUDED_ASYNC_TYPES.has(type)) return;
if (!parentContext || EXCLUDED_ASYNC_TYPES.has(type)) return;
const ref = getContextRef(parentContext, triggerAsyncId);
const ref = getContextRef(parentContext, triggerAsyncId);
const refContext = executionContextMap.get(ref);
// Setting child process entry as ref to parent context
executionContextMap.set(asyncId, {
ref,
type,
created: Date.now()
});
// Setting child process entry as ref to parent context
executionContextMap.set(asyncId, {
ref,
...(refContext.monitor && {
created: Date.now(),
type
})
});
const { context = {}, children = [], ...meta } = executionContextMap.get(ref);
// Adding current async as child to parent context in order to control cleanup better
executionContextMap.set(ref, {
...meta,
context,
children: [...children, asyncId]
});
// Adding current async as child to parent context in order to control cleanup better
refContext.children ? refContext.children.push(asyncId) : refContext.children = [asyncId];
};

@@ -61,7 +58,9 @@

const onChildProcessDestroy = (executionContextMap, asyncId, ref) => {
const { children: parentChildren, context, ...meta } = executionContextMap.get(ref);
const children = parentChildren.filter((id) => id !== asyncId);
if (!executionContextMap.has(ref)) return;
const refContext = executionContextMap.get(ref);
const filtered = refContext.children.filter((id) => id !== asyncId);
// Parent context will be released upon last child removal
if (!children.length) {
if (!filtered.length) {
suspend(() => executionContextMap.delete(ref));

@@ -72,7 +71,3 @@

executionContextMap.set(ref, {
...meta,
context,
children
});
refContext.children = filtered;
};

@@ -85,4 +80,4 @@

*/
const destroy = (executionContextMap) => (asyncId)=> {
if (!executionContextMap.has(asyncId)) { return; }
const destroy = (executionContextMap) => (asyncId) => {
if (!executionContextMap.has(asyncId)) return;

@@ -92,3 +87,5 @@ const { children = [], ref } = executionContextMap.get(asyncId);

// As long as any root process holds none finished child process, we keep it alive
if (children.length) { return; }
if (children.length) {
return;
}

@@ -108,3 +105,2 @@ // Child context's will unregister themselves from root context

/**

@@ -122,2 +118,2 @@ * The Create hooks callback to be passed to "async_hooks"

module.exports = { create };
module.exports = { create, onChildProcessDestroy };

@@ -1,126 +0,6 @@

const asyncHooks = require('async_hooks');
const ExecutionContextResource = require('./lib/ExecutionContextResource');
const { isProduction, monitorMap } = require('./lib');
const { create: createHooks } = require('./hooks');
const { ExecutionContextErrors } = require('./constants');
const ExecutionContext = require('./ExecutionContext');
/**
* Handles execution context error, throws when none production
* @param code
*/
const handleError = (code) => {
if (!isProduction()) {
throw code;
}
// Ensures only 1 instance exists per runtime.
global.ExecutionContext = global.ExecutionContext || new ExecutionContext();
console.warn(code);
};
/**
* The Execution Context API
* @return {ExecutionContextAPI}
*/
const createExecutionContext = () => {
/**
* The global service context execution map
* @type ExecutionContextMap
*/
const executionContextMap = new Map();
// Sets node async hooks setup
asyncHooks.createHook(
createHooks(executionContextMap)
).enable();
const Context = {
/**
* Creates an execution context for the current asyncId process.
* This will expose Context get / update at any point after.
* @param {Object} initialContext - The initial context to be used
* @returns void
*/
create: (initialContext = {}) => {
const asyncId = asyncHooks.executionAsyncId();
// Creation is allowed once per execution context
if (executionContextMap.has(asyncId)) handleError(ExecutionContextErrors.CONTEXT_ALREADY_DECLARED);
executionContextMap.set(asyncId, {
asyncId,
context: { ...initialContext, executionId: asyncId },
created: Date.now(),
children: []
});
},
/**
* Updates the current async process context.
* @param {Object} update - The update to apply on the current process context.
* @returns void
*/
update: (update = {}) => {
const asyncId = asyncHooks.executionAsyncId();
if (!executionContextMap.has(asyncId)) handleError(ExecutionContextErrors.CONTEXT_DOES_NOT_EXISTS);
const contextData = executionContextMap.get(asyncId);
// Update target is always the root context, ref updates will need to be channeled
const targetContextData = contextData.ref
? executionContextMap.get(contextData.ref)
: contextData;
targetContextData.context = { ...targetContextData.context, ...update };
},
/**
* Gets the current async process execution context.
* @returns {Object}
*/
get: () => {
const asyncId = asyncHooks.executionAsyncId();
if (!executionContextMap.has(asyncId)) handleError(ExecutionContextErrors.CONTEXT_DOES_NOT_EXISTS);
const { context = {}, ref } = executionContextMap.get(asyncId);
if (ref) {
// Ref will be used to point out on the root context
return executionContextMap.get(ref).context;
}
// Root context
return context;
},
/**
* Runs a given function within "AsyncResource" context, this will ensure the function executed within a uniq execution context.
* @param {Function} fn - The function to run.
* @param {Object} initialContext - The initial context to expose to the function execution
*/
run: (fn, initialContext) => {
const resource = new ExecutionContextResource();
resource.runInAsyncScope(() => {
Context.create(initialContext);
fn();
});
},
/**
* Monitors current execution map usage
* @return {ExecutionMapUsage}
*/
monitor: () => {
return monitorMap(executionContextMap);
}
};
return Context;
};
global.ExecutionContext = global.ExecutionContext || createExecutionContext();
module.exports = global.ExecutionContext;

@@ -0,1 +1,3 @@

const ExecutionContextResource = require('./ExecutionContextResource');
/**

@@ -18,6 +20,17 @@ * The production environment

module.exports = {
ExecutionContextResource,
env,
/**
* Checks if current environment matches production.
* @param {String} environment - The current environment.
* @return {Boolean}
*/
isProduction: (environment = env) => environment === PRODUCTION,
/**
* Checks if a given value is undefined.
* @param {String} thing that thing to check.
* @return {Boolean}
*/
isUndefined: (thing) => [null, undefined].includes(thing),

@@ -27,3 +40,3 @@

* Returns a monitoring report over the "executionContext" memory usage.
* @param {ExecutionContextMap} executionContextMap The execution map to monitor
* @param {ExecutionContextMap} executionContextMap The execution map to monitor.
* @return {ExecutionMapUsage}

@@ -35,5 +48,6 @@ */

.filter(({ children }) => !!children)
.map(({ asyncId, created, children, context = {} }) => ({
.map(({ asyncId, created, children, domain, context = {} }) => ({
asyncId,
created,
domain,
contextSize: JSON.stringify(context).length,

@@ -40,0 +54,0 @@ duration: getDuration(now, created),

const lib = require ('.');
const { ExecutionContextErrors } = require('../ExecutionContext/constants');
const Context = require('../');

@@ -38,5 +39,13 @@

describe('monitorMap', () => {
describe('When context is not configured to tracking', () => {
it('Throws miss configured error', () => {
expect(() => Context.monitor()).toThrow(ExecutionContextErrors.MONITOR_MISS_CONFIGURATION);
});
});
describe('When no context is open', () => {
let report;
beforeEach(() => {
Context.configure({ monitor: true });
report = Context.monitor();

@@ -43,0 +52,0 @@ });

@@ -1,91 +0,3 @@

interface ExecutionContext {
ref? :number;
children?: number[];
context?: object;
}
type ExecutionContextMap = Map<number, ExecutionContext>;
interface HookCallbacks {
/**
* Called when a class is constructed that has the possibility to emit an asynchronous event.
* @param asyncId a unique ID for the async resource
* @param type the type of the async resource
* @param triggerAsyncId the unique ID of the async resource in whose execution context this async resource was created
* @param resource reference to the resource representing the async operation, needs to be released during destroy
*/
init?(asyncId: number, type: string, triggerAsyncId: number, resource: object): void;
/**
* Called when a promise has resolve() called. This may not be in the same execution id
* as the promise itself.
* @param asyncId the unique id for the promise that was resolve()d.
*/
promiseResolve?(asyncId: number): void;
/**
* Called after the resource corresponding to asyncId is destroyed
* @param asyncId a unique ID for the async resource
*/
destroy?(asyncId: number): void;
}
interface ExecutionMapUsageBaseEntry {
asyncId: number;
created: number;
duration: number;
}
interface ExecutionMapUsageChildEntry extends ExecutionMapUsageBaseEntry {
type: string;
}
interface ExecutionMapUsageEntry extends ExecutionMapUsageBaseEntry {
asyncId: number;
children: ExecutionMapUsageChildEntry[];
}
interface ExecutionMapUsage {
size: number;
entries: ExecutionMapUsageEntry[];
}
interface ExecutionContextAPI {
/**
* Creates an execution context for the current asyncId process.
* @param initialContext
*/
create(initialContext: object): void;
/**
* Updates the current async process context.
* @param update
*/
update(update: object): void;
/**
* Gets the current async process execution context.
*/
get(): object;
/**
* Runs a given function within an async resource context
* @param fn
* @param initialContext
*/
run(fn: Function, initialContext: object): void;
/**
* Monitors the current execution map usage
*/
monitor(): ExecutionMapUsage;
}
export {
ExecutionContextMap,
ExecutionContextAPI,
ExecutionMapUsage,
ExecutionMapUsageEntry
}
export * from './lib/types';
export * from './hooks/types';
export * from './ExecutionContext/types';

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.