From 6f1e32284d5c2e22f8ad802a352e7f17c9a3d59a Mon Sep 17 00:00:00 2001 From: Philipp Kunz Date: Wed, 18 Jan 2023 17:45:19 +0100 Subject: [PATCH] fix(core): update --- .gitlab-ci.yml | 44 +++++-------- .vscode/launch.json | 24 +------- npmextra.json | 2 +- package.json | 5 +- readme.md | 6 +- test/test.asyncexecutionstack.both.ts | 29 +++++++++ test/test.fastmap.both.ts | 12 ++-- ts/00_commitinfo_data.ts | 2 +- ts/index.ts | 2 +- ts/lik.asyncexecutionstack.ts | 89 ++++++++++++++++++++++----- ts/lik.interestmap.interest.ts | 5 +- ts/lik.interestmap.ts | 1 - ts/lik.objectmap.ts | 8 +-- 13 files changed, 143 insertions(+), 86 deletions(-) create mode 100644 test/test.asyncexecutionstack.both.ts diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 88889cf..c96d0c9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,29 +12,25 @@ stages: - release - metadata +before_script: + - pnpm install -g pnpm + - pnpm install -g @shipzone/npmci + - npmci npm prepare + +# ==================== +# security stage +# ==================== # ==================== # security stage # ==================== -mirror: - stage: security - script: - - npmci git mirror - only: - - tags - tags: - - lossless - - docker - - notpriv - auditProductionDependencies: image: registry.gitlab.com/hosttoday/ht-docker-node:npmci stage: security script: - - npmci npm prepare - - npmci command npm install --production --ignore-scripts - - npmci command npm config set registry https://registry.npmjs.org - - npmci command npm audit --audit-level=high --only=prod --production + - npmci command npm config set registry https://registry.npmjs.org + - npmci command pnpm audit --audit-level=high --prod tags: + - lossless - docker allow_failure: true @@ -42,11 +38,10 @@ auditDevDependencies: image: registry.gitlab.com/hosttoday/ht-docker-node:npmci stage: security script: - - npmci npm prepare - - npmci command npm install --ignore-scripts - npmci command npm config set registry https://registry.npmjs.org - - npmci command npm audit --audit-level=high --only=dev + - npmci command pnpm audit --audit-level=high --dev tags: + - lossless - docker allow_failure: true @@ -57,7 +52,6 @@ auditDevDependencies: testStable: stage: test script: - - npmci npm prepare - npmci node install stable - npmci npm install - npmci npm test @@ -68,10 +62,9 @@ testStable: testBuild: stage: test script: - - npmci npm prepare - npmci node install stable - npmci npm install - - npmci command npm run build + - npmci npm build coverage: /\d+.?\d+?\%\s*coverage/ tags: - docker @@ -97,10 +90,9 @@ codequality: only: - tags script: - - npmci command npm install -g tslint typescript + - npmci command npm install -g typescript - npmci npm prepare - npmci npm install - - npmci command "tslint -c tslint.json ./ts/**/*.ts" tags: - lossless - docker @@ -120,11 +112,9 @@ trigger: pages: stage: metadata script: - - npmci node install lts - - npmci command npm install -g @gitzone/tsdoc - - npmci npm prepare + - npmci node install stable - npmci npm install - - npmci command tsdoc + - npmci command npm run buildDocs tags: - lossless - docker diff --git a/.vscode/launch.json b/.vscode/launch.json index 112db52..d4ccaed 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,28 +2,10 @@ "version": "0.2.0", "configurations": [ { - "name": "current file", - "type": "node", + "command": "# instrumented", + "name": "Run instrumented terminal", "request": "launch", - "args": [ - "${relativeFile}" - ], - "runtimeArgs": ["-r", "@gitzone/tsrun"], - "cwd": "${workspaceRoot}", - "protocol": "inspector", - "internalConsoleOptions": "openOnSessionStart" - }, - { - "name": "test.ts", - "type": "node", - "request": "launch", - "args": [ - "test/test.ts" - ], - "runtimeArgs": ["-r", "@gitzone/tsrun"], - "cwd": "${workspaceRoot}", - "protocol": "inspector", - "internalConsoleOptions": "openOnSessionStart" + "type": "node-terminal" } ] } diff --git a/npmextra.json b/npmextra.json index e81c5cf..a573e32 100644 --- a/npmextra.json +++ b/npmextra.json @@ -9,7 +9,7 @@ "githost": "gitlab.com", "gitscope": "pushrocks", "gitrepo": "lik", - "shortDescription": "light little helpers for node", + "description": "light little helpers for node", "npmPackagename": "@pushrocks/lik", "license": "MIT" } diff --git a/package.json b/package.json index 074f7e7..a603e3f 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "type": "module", "scripts": { "test": "(tstest test/)", - "build": "(tsbuild --web --allowimplicitany && tsbundle npm)" + "build": "(tsbuild --web --allowimplicitany && tsbundle npm)", + "buildDocs": "tsdoc" }, "repository": { "type": "git", @@ -53,4 +54,4 @@ "browserslist": [ "last 1 chrome versions" ] -} +} \ No newline at end of file diff --git a/readme.md b/readme.md index 36003e1..b4cf5ae 100644 --- a/readme.md +++ b/readme.md @@ -21,7 +21,6 @@ Code Style | [![Code Style](https://badgen.net/badge/style/prettier/purple)](htt PackagePhobia (total standalone install weight) | [![PackagePhobia](https://badgen.net/packagephobia/install/@pushrocks/lik)](https://lossless.cloud) PackagePhobia (package size on registry) | [![PackagePhobia](https://badgen.net/packagephobia/publish/@pushrocks/lik)](https://lossless.cloud) BundlePhobia (total size when bundled) | [![BundlePhobia](https://badgen.net/bundlephobia/minzip/@pushrocks/lik)](https://lossless.cloud) -Platform support | [![Supports Windows 10](https://badgen.net/badge/supports%20Windows%2010/yes/green?icon=windows)](https://lossless.cloud) [![Supports Mac OS X](https://badgen.net/badge/supports%20Mac%20OS%20X/yes/green?icon=apple)](https://lossless.cloud) ## Usage @@ -48,7 +47,6 @@ We are always happy for code contributions. If you are not the code contributing For further information read the linked docs at the top of this readme. -> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh) +## Legal +> MIT licensed | **©** [Task Venture Capital GmbH](https://task.vc) | By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy) - -[![repo-footer](https://lossless.gitlab.io/publicrelations/repofooter.svg)](https://maintainedby.lossless.com) diff --git a/test/test.asyncexecutionstack.both.ts b/test/test.asyncexecutionstack.both.ts new file mode 100644 index 0000000..11c3e9c --- /dev/null +++ b/test/test.asyncexecutionstack.both.ts @@ -0,0 +1,29 @@ +import { tap, expect } from '@pushrocks/tapbundle'; +import * as lik from '../ts/index.js'; + +let testAsyncExecutionStack: lik.AsyncExecutionStack; + +tap.test('should create a valid instance of AsyncExectionStack', async () => { + testAsyncExecutionStack = new lik.AsyncExecutionStack(); + expect(testAsyncExecutionStack).toBeInstanceOf(lik.AsyncExecutionStack); +}); + +tap.test('should run in parallel', async (toolsArg) => { + await testAsyncExecutionStack.getExclusiveExecutionSlot(async () => { + await toolsArg.delayFor(2000); + console.log('should run first'); + }, 2500); + testAsyncExecutionStack.getNonExclusiveExecutionSlot(async () => { + await toolsArg.delayFor(2000); + console.log('should run third'); + }, 2500); + testAsyncExecutionStack.getNonExclusiveExecutionSlot(async () => { + await toolsArg.delayFor(1000); + console.log('should run second'); + }, 2500); + await testAsyncExecutionStack.getExclusiveExecutionSlot(async () => { + console.log('should run fourth'); + }, 0); +}); + +tap.start(); diff --git a/test/test.fastmap.both.ts b/test/test.fastmap.both.ts index 6de09b4..7b4b2f8 100644 --- a/test/test.fastmap.both.ts +++ b/test/test.fastmap.both.ts @@ -14,15 +14,17 @@ tap.test('should find an entry', async () => { }>(); fastmap.addToMap('heythere', { value1: 'heyho', - value2: 'heyho2' - }) + value2: 'heyho2', + }); fastmap.addToMap('heythere2', { value1: 'heyho3', - value2: 'heyho4' + value2: 'heyho4', }); - const result = await fastmap.find(async (itemArg)=> {return itemArg.value2 === 'heyho4'}); + const result = await fastmap.find(async (itemArg) => { + return itemArg.value2 === 'heyho4'; + }); expect(result.value1).toEqual('heyho3'); }); -tap.start(); \ No newline at end of file +tap.start(); diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 8706891..989f767 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@pushrocks/lik', - version: '6.0.1', + version: '6.0.2', description: 'light little helpers for node' } diff --git a/ts/index.ts b/ts/index.ts index c935f47..48c7c83 100644 --- a/ts/index.ts +++ b/ts/index.ts @@ -1,4 +1,4 @@ -export * from './lik.asyncexecutionstack.js' +export * from './lik.asyncexecutionstack.js'; export * from './lik.fastmap.js'; export * from './lik.interestmap.js'; export * from './lik.interestmap.interest.js'; diff --git a/ts/lik.asyncexecutionstack.ts b/ts/lik.asyncexecutionstack.ts index 5aa9072..aee3cf1 100644 --- a/ts/lik.asyncexecutionstack.ts +++ b/ts/lik.asyncexecutionstack.ts @@ -1,25 +1,82 @@ -import * as plugins from './lik.plugins.js' +import * as plugins from './lik.plugins.js'; + +interface IExecutionSlot { + executionDeferred: plugins.smartpromise.Deferred; + funcToExecute: () => Promise; + timeout?: number; + mode: 'exclusive' | 'nonexclusive'; +} /** * allows for avoiding race condition */ export class AsyncExecutionStack { - public currentExecutions: Promise[] = []; - public async getExclusiveExecutionSlot(funcArg: () => Promise, timeoutArg: number) { - const executionDeferred = plugins.smartpromise.defer(); - this.currentExecutions.push(executionDeferred.promise); - for (const promiseArg of this.currentExecutions) { - if (promiseArg !== executionDeferred.promise) { - await promiseArg; - } else { - if (timeoutArg) { - await Promise.race([funcArg(),plugins.smartdelay.delayFor(timeoutArg)]) + private executionSlots: IExecutionSlot[] = []; + public async getExclusiveExecutionSlot(funcArg: () => Promise, timeoutArg?: number) { + const executionDeferred = plugins.smartpromise.defer(); + const executionSlot: IExecutionSlot = { + funcToExecute: funcArg, + executionDeferred, + timeout: timeoutArg, + mode: 'exclusive', + }; + this.executionSlots.push(executionSlot); + this.processExecutionSlots(); + return executionDeferred.promise; + } + public async getNonExclusiveExecutionSlot( + funcArg: () => Promise, + timeoutArg?: number + ) { + const executionDeferred = plugins.smartpromise.defer(); + const executionSlot: IExecutionSlot = { + funcToExecute: funcArg, + executionDeferred, + timeout: timeoutArg, + mode: 'nonexclusive', + }; + this.executionSlots.push(executionSlot); + this.processExecutionSlots(); + return executionDeferred.promise; + } + + private currentlyExecutingDeferred: plugins.smartpromise.Deferred; + private async processExecutionSlots() { + if (this.currentlyExecutingDeferred) { + return; + } + this.currentlyExecutingDeferred = plugins.smartpromise.defer(); + let nonExclusiveRunningSlots: IExecutionSlot[] = []; + const checkNonExclusiveRunningSlots = async (cleanArg = false) => { + if (nonExclusiveRunningSlots.length > 100 || cleanArg) { + await Promise.all(nonExclusiveRunningSlots.map(nonExclusiveRunningSlotArg => nonExclusiveRunningSlotArg.executionDeferred.promise)); + nonExclusiveRunningSlots = []; + } + }; + while (this.executionSlots.length > 0) { + const nextExecutionSlot = this.executionSlots.shift(); + const runNextExecution = async () => { + if (nextExecutionSlot.timeout) { + const result = await Promise.race([ + nextExecutionSlot.funcToExecute(), + plugins.smartdelay.delayFor(nextExecutionSlot.timeout), + ]); + nextExecutionSlot.executionDeferred.resolve(result); } else { - await funcArg(); + nextExecutionSlot.executionDeferred.resolve(await nextExecutionSlot.funcToExecute()); } - executionDeferred.resolve(); - this.currentExecutions.shift(); + }; + if (nextExecutionSlot.mode === 'exclusive') { + await checkNonExclusiveRunningSlots(true); + await runNextExecution(); + } else { + nonExclusiveRunningSlots.push(nextExecutionSlot); + await checkNonExclusiveRunningSlots(false); + runNextExecution(); } } - }; -} \ No newline at end of file + this.currentlyExecutingDeferred.resolve(); + this.currentlyExecutingDeferred = null; + + } +} diff --git a/ts/lik.interestmap.interest.ts b/ts/lik.interestmap.interest.ts index 9a7d413..d0b8ed9 100644 --- a/ts/lik.interestmap.interest.ts +++ b/ts/lik.interestmap.interest.ts @@ -28,9 +28,8 @@ export class Interest { return this.comparisonFunc(this.originalInterest); } - private interestDeferred: plugins.smartpromise.Deferred< - DTInterestFullfillment - > = new plugins.smartpromise.Deferred(); + private interestDeferred: plugins.smartpromise.Deferred = + new plugins.smartpromise.Deferred(); public interestFullfilled = this.interestDeferred.promise; /** diff --git a/ts/lik.interestmap.ts b/ts/lik.interestmap.ts index 28d7966..d7451d0 100644 --- a/ts/lik.interestmap.ts +++ b/ts/lik.interestmap.ts @@ -8,7 +8,6 @@ Subssequent interests will be mapped to the same interest which is then is only fullfilled once. =========== */ - import * as plugins from './lik.plugins.js'; import { ObjectMap } from './lik.objectmap.js'; import { Interest } from './lik.interestmap.interest.js'; diff --git a/ts/lik.objectmap.ts b/ts/lik.objectmap.ts index 2637beb..60d1d8d 100644 --- a/ts/lik.objectmap.ts +++ b/ts/lik.objectmap.ts @@ -85,7 +85,7 @@ export class ObjectMap { this.addMappedUnique(uniqueKey, objectArg); this.eventSubject.next({ operation: 'add', - payload: objectArg + payload: objectArg, }); return uniqueKey; } @@ -140,7 +140,7 @@ export class ObjectMap { /** * finds a specific element and then removes it */ - public async findOneAndRemove(findFunction: IObjectmapFindFunction): Promise { + public async findOneAndRemove(findFunction: IObjectmapFindFunction): Promise { const foundElement = await this.find(findFunction); if (foundElement) { this.remove(foundElement); @@ -176,7 +176,7 @@ export class ObjectMap { const removedItem = this.fastMap.removeFromMap(keyToUse); this.eventSubject.next({ operation: 'remove', - payload: removedItem + payload: removedItem, }); return removedItem; } @@ -209,7 +209,7 @@ export class ObjectMap { const removedObject = this.fastMap.removeFromMap(keyArg); this.eventSubject.next({ operation: 'remove', - payload: removedObject + payload: removedObject, }); return removedObject; }