From e6077f21217705f87db36640e159b234abee8d6d Mon Sep 17 00:00:00 2001 From: Andrii Glushko Date: Wed, 1 Jul 2026 11:05:12 +0200 Subject: [PATCH] CRP-6817: Add User-related columns to all applicable DB tables --- package-lock.json | 12 +++------ src/IMQRequestContext.ts | 57 ++++++++++++++++++++++++++++++++++++++++ src/IMQService.ts | 8 ++++++ src/index.ts | 1 + 4 files changed, 70 insertions(+), 8 deletions(-) create mode 100644 src/IMQRequestContext.ts diff --git a/package-lock.json b/package-lock.json index 2f26710..9936799 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "2.0.26", "license": "GPL-3.0-only", "dependencies": { - "@imqueue/core": "^2.0.25", + "@imqueue/core": "^2.0.26", "@types/node": "^24.9.1", "acorn": "^8.15.0", "farmhash": "^5.0.1", @@ -67,7 +67,6 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -343,9 +342,9 @@ } }, "node_modules/@imqueue/core": { - "version": "2.0.25", - "resolved": "https://registry.npmjs.org/@imqueue/core/-/core-2.0.25.tgz", - "integrity": "sha512-VzIom+YPyFYzANOkO8SOWMG95D1wo/iPTBN+pbCW93umC+IsTWBoIEH317PY7Y4OFwXmhq+8cpxv4ViOr3fZdw==", + "version": "2.0.26", + "resolved": "https://registry.npmjs.org/@imqueue/core/-/core-2.0.26.tgz", + "integrity": "sha512-4Ecy/23+mVcSkeNYJGbcj1XaU4Hicnu9MQTLejOhuhVrgspOWrYr/GY7dDlF7amWKw1zFN8FehRFdszgz1YxPQ==", "license": "GPL-3.0-only", "dependencies": { "ioredis": "^5.8.2" @@ -708,7 +707,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz", "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -903,7 +901,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", @@ -3521,7 +3518,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/src/IMQRequestContext.ts b/src/IMQRequestContext.ts new file mode 100644 index 0000000..1c9d28e --- /dev/null +++ b/src/IMQRequestContext.ts @@ -0,0 +1,57 @@ +/*! + * IMQRequestContext implementation + * + * I'm Queue Software Project + * Copyright (C) 2025 imqueue.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * If you want to use this code in a closed source (commercial) project, you can + * purchase a proprietary commercial license. Please contact us at + * to get commercial licensing options. + */ +import { AsyncLocalStorage } from 'node:async_hooks'; +import { IMQMetadata } from './IMQMetadata'; +import { IMQRPCRequest } from './IMQRPCRequest'; + +const storage = new AsyncLocalStorage(); + +/** + * Runs the given function with `request` bound to the current async execution + * context, so any code reached from it (and its asynchronous continuations) can + * access the in-flight request's metadata via `currentMetadata()` without + * threading it through call signatures. + * + * The binding is scoped to the function: it is established for the duration of + * the call and automatically removed afterwards, which keeps concurrent + * requests isolated from one another. + * + * @param {IMQRPCRequest} request - the request to bind for this execution + * @param {() => T} fn - the work to run within the bound context + * @return {T} + */ +export function runWithRequest(request: IMQRPCRequest, fn: () => T): T { + return storage.run(request, fn); +} + +/** + * Returns the metadata of the in-flight IMQ request for the current async + * execution, if any. Returns `undefined` outside of a `runWithRequest()` scope. + * The transport carries metadata as an opaque bag; callers interpret its fields. + * + * @return {IMQMetadata | undefined} + */ +export function currentMetadata(): IMQMetadata | undefined { + return storage.getStore()?.metadata; +} diff --git a/src/IMQService.ts b/src/IMQService.ts index 4103f8a..11d6c81 100644 --- a/src/IMQService.ts +++ b/src/IMQService.ts @@ -47,6 +47,7 @@ import { import * as os from 'os'; import { ArgDescription } from './IMQRPCDescription'; import { IMQBeforeCall, IMQAfterCall } from './IMQRPCOptions'; +import { runWithRequest } from './IMQRequestContext'; import * as http from 'node:http'; const cluster: any = require('cluster'); @@ -170,6 +171,13 @@ export abstract class IMQService { private async handleRequest( request: IMQRPCRequest, id: string, + ): Promise { + return runWithRequest(request, () => this.processRequest(request, id)); + } + + private async processRequest( + request: IMQRPCRequest, + id: string, ): Promise { const logger = this.options.logger || console; const method = request.method; diff --git a/src/index.ts b/src/index.ts index 06de58b..a5f9f59 100644 --- a/src/index.ts +++ b/src/index.ts @@ -33,3 +33,4 @@ export * from './IMQLock'; export * from './IMQService'; export * from './IMQClient'; export * from './IMQMetadata'; +export * from './IMQRequestContext';