From 8405f44bd9249dbd3970a737b934027c7a28bf01 Mon Sep 17 00:00:00 2001 From: Boki Date: Sat, 21 Jun 2025 20:38:16 -0400 Subject: [PATCH] fixed libs ready for new data-injection --- .env | 2 +- .../src/handlers/ib/ib.handler.ts | 2 +- .../ib/operations/exchanges.operations.ts | 2 +- .../ib/operations/symbols.operations.ts | 2 +- .../handlers/proxy/shared/proxy-manager.ts | 6 - .../qm/operations/exchanges.operations.ts | 2 +- .../qm/operations/spider.operations.ts | 2 +- .../src/handlers/qm/qm.handler.ts | 22 ++-- apps/data-ingestion/src/index.ts | 2 +- bun.lock | 75 +----------- check-db-usage.ts | 59 ---------- libs/core/di/src/connection-factory.ts | 3 + libs/core/handlers/package.json | 1 + libs/core/handlers/src/index.ts | 4 +- libs/core/handlers/src/types/types.ts | 85 ++------------ libs/core/types/src/handler-registry.ts | 111 ++++++++++++++++++ libs/core/types/src/handlers.ts | 83 +++++++++++++ libs/core/types/src/index.ts | 17 +++ libs/data/mongodb/src/client.ts | 8 ++ libs/services/queue/package.json | 1 - libs/services/queue/src/index.ts | 4 +- libs/services/queue/src/queue-manager.ts | 2 +- libs/services/queue/src/queue.ts | 4 +- libs/services/queue/src/types.ts | 8 +- scripts/build-libs.sh | 11 +- 25 files changed, 277 insertions(+), 241 deletions(-) delete mode 100644 apps/data-ingestion/src/handlers/proxy/shared/proxy-manager.ts delete mode 100644 check-db-usage.ts create mode 100644 libs/core/types/src/handler-registry.ts create mode 100644 libs/core/types/src/handlers.ts diff --git a/.env b/.env index e648d2f..1ffd587 100644 --- a/.env +++ b/.env @@ -5,7 +5,7 @@ # Core Application Settings NODE_ENV=development LOG_LEVEL=debug -LOG_HIDE_OBJECT=true +LOG_HIDE_OBJECT=false # Data Service Configuration DATA_SERVICE_PORT=2001 diff --git a/apps/data-ingestion/src/handlers/ib/ib.handler.ts b/apps/data-ingestion/src/handlers/ib/ib.handler.ts index 1a3edbc..bc21ac8 100644 --- a/apps/data-ingestion/src/handlers/ib/ib.handler.ts +++ b/apps/data-ingestion/src/handlers/ib/ib.handler.ts @@ -7,7 +7,7 @@ import { handlerRegistry, type HandlerConfigWithSchedule, } from '@stock-bot/queue'; -import type { ServiceContainer } from '@stock-bot/connection-factory'; +import type { ServiceContainer } from '@stock-bot/di'; const logger = getLogger('ib-provider'); diff --git a/apps/data-ingestion/src/handlers/ib/operations/exchanges.operations.ts b/apps/data-ingestion/src/handlers/ib/operations/exchanges.operations.ts index 85ded3c..4b173a1 100644 --- a/apps/data-ingestion/src/handlers/ib/operations/exchanges.operations.ts +++ b/apps/data-ingestion/src/handlers/ib/operations/exchanges.operations.ts @@ -2,7 +2,7 @@ * IB Exchanges Operations - Fetching exchange data from IB API */ import { OperationContext } from '@stock-bot/di'; -import type { ServiceContainer } from '@stock-bot/connection-factory'; +import type { ServiceContainer } from '@stock-bot/di'; import { IB_CONFIG } from '../shared/config'; diff --git a/apps/data-ingestion/src/handlers/ib/operations/symbols.operations.ts b/apps/data-ingestion/src/handlers/ib/operations/symbols.operations.ts index cfd076f..64a5a44 100644 --- a/apps/data-ingestion/src/handlers/ib/operations/symbols.operations.ts +++ b/apps/data-ingestion/src/handlers/ib/operations/symbols.operations.ts @@ -2,7 +2,7 @@ * IB Symbols Operations - Fetching symbol data from IB API */ import { OperationContext } from '@stock-bot/di'; -import type { ServiceContainer } from '@stock-bot/connection-factory'; +import type { ServiceContainer } from '@stock-bot/di'; import { IB_CONFIG } from '../shared/config'; diff --git a/apps/data-ingestion/src/handlers/proxy/shared/proxy-manager.ts b/apps/data-ingestion/src/handlers/proxy/shared/proxy-manager.ts deleted file mode 100644 index 4a02dc4..0000000 --- a/apps/data-ingestion/src/handlers/proxy/shared/proxy-manager.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Proxy Manager - Simplified without stats tracking - */ - -// This file is kept for compatibility but ProxyStatsManager has been removed -// All proxy management is now handled by the global ProxyManager in @stock-bot/utils \ No newline at end of file diff --git a/apps/data-ingestion/src/handlers/qm/operations/exchanges.operations.ts b/apps/data-ingestion/src/handlers/qm/operations/exchanges.operations.ts index 05ae48e..be1eeb6 100644 --- a/apps/data-ingestion/src/handlers/qm/operations/exchanges.operations.ts +++ b/apps/data-ingestion/src/handlers/qm/operations/exchanges.operations.ts @@ -3,7 +3,7 @@ */ import { OperationContext } from '@stock-bot/di'; -import type { ServiceContainer } from '@stock-bot/connection-factory'; +import type { ServiceContainer } from '@stock-bot/di'; import { initializeQMResources } from './session.operations'; diff --git a/apps/data-ingestion/src/handlers/qm/operations/spider.operations.ts b/apps/data-ingestion/src/handlers/qm/operations/spider.operations.ts index ff70866..b0a42be 100644 --- a/apps/data-ingestion/src/handlers/qm/operations/spider.operations.ts +++ b/apps/data-ingestion/src/handlers/qm/operations/spider.operations.ts @@ -7,7 +7,7 @@ import { QueueManager } from '@stock-bot/queue'; import { QMSessionManager } from '../shared/session-manager'; import { QM_SESSION_IDS } from '../shared/config'; -import type { ServiceContainer } from '@stock-bot/connection-factory'; +import type { ServiceContainer } from '@stock-bot/di'; import type { SymbolSpiderJob, SpiderResult } from '../shared/types'; import { initializeQMResources } from './session.operations'; import { searchQMSymbolsAPI } from './symbols.operations'; diff --git a/apps/data-ingestion/src/handlers/qm/qm.handler.ts b/apps/data-ingestion/src/handlers/qm/qm.handler.ts index 87b8968..f38b310 100644 --- a/apps/data-ingestion/src/handlers/qm/qm.handler.ts +++ b/apps/data-ingestion/src/handlers/qm/qm.handler.ts @@ -3,11 +3,10 @@ import { Handler, Operation, QueueSchedule, - handlerRegistry, - createJobHandler, type ExecutionContext, type HandlerConfigWithSchedule } from '@stock-bot/handlers'; +import { handlerRegistry, createJobHandler } from '@stock-bot/types'; import type { IDataIngestionServices, IExecutionContext } from '@stock-bot/di'; import type { SymbolSpiderJob } from './shared/types'; @@ -87,25 +86,26 @@ export class QMHandler extends BaseHandler { async spiderSymbolSearch(payload: SymbolSpiderJob, context: ExecutionContext): Promise { this.logger.info('Starting QM spider symbol search', { payload }); - // Direct access to typed dependencies - const spiderCollection = this.mongodb.collection('qm_spider_results'); - - // Store spider job info + // Store spider job info in cache (temporary data) + const spiderJobId = `spider:qm:${Date.now()}:${Math.random().toString(36).substr(2, 9)}`; const spiderResult = { payload, - startTime: new Date(), - status: 'started' + startTime: new Date().toISOString(), + status: 'started', + jobId: spiderJobId }; - await spiderCollection.insertOne(spiderResult); + // Store in cache with 1 hour TTL (temporary data) + await this.cache.set(spiderJobId, spiderResult, 3600); + this.logger.debug('Spider job stored in cache', { spiderJobId, ttl: 3600 }); // Schedule follow-up processing if needed - await this.scheduleOperation('search-symbols', { source: 'spider' }, 5000); + await this.scheduleOperation('search-symbols', { source: 'spider', spiderJobId }, 5000); return { success: true, message: 'QM spider search initiated', - spiderJobId: spiderResult._id + spiderJobId }; } } diff --git a/apps/data-ingestion/src/index.ts b/apps/data-ingestion/src/index.ts index ae487df..a69a8c3 100644 --- a/apps/data-ingestion/src/index.ts +++ b/apps/data-ingestion/src/index.ts @@ -17,7 +17,7 @@ import { disposeDataIngestionServices, type IDataIngestionServices } from '@stock-bot/di'; -import { handlerRegistry } from '@stock-bot/handlers'; +import { handlerRegistry } from '@stock-bot/types'; // Local imports import { createRoutes } from './routes/create-routes'; diff --git a/bun.lock b/bun.lock index e580bf8..d0ea173 100644 --- a/bun.lock +++ b/bun.lock @@ -151,14 +151,8 @@ "name": "@stock-bot/di", "version": "1.0.0", "dependencies": { - "@stock-bot/cache": "workspace:*", "@stock-bot/config": "workspace:*", "@stock-bot/logger": "workspace:*", - "@stock-bot/mongodb": "workspace:*", - "@stock-bot/postgres": "workspace:*", - "@stock-bot/queue": "workspace:*", - "mongodb": "^6.3.0", - "pg": "^8.11.3", }, "devDependencies": { "@types/pg": "^8.10.7", @@ -171,6 +165,7 @@ "@stock-bot/config": "workspace:*", "@stock-bot/di": "workspace:*", "@stock-bot/logger": "workspace:*", + "@stock-bot/types": "workspace:*", }, "devDependencies": { "@types/node": "^20.11.0", @@ -324,7 +319,6 @@ "version": "1.0.0", "dependencies": { "@stock-bot/cache": "*", - "@stock-bot/handlers": "*", "@stock-bot/logger": "*", "@stock-bot/types": "*", "bullmq": "^5.0.0", @@ -351,20 +345,9 @@ "dependencies": { "@stock-bot/cache": "workspace:*", "@stock-bot/config": "workspace:*", - "@stock-bot/di": "workspace:*", "@stock-bot/http": "workspace:*", "@stock-bot/logger": "workspace:*", - "@stock-bot/mongodb": "workspace:*", - "@stock-bot/postgres": "workspace:*", "@stock-bot/types": "workspace:*", - "axios": "^1.7.7", - "axios-rate-limit": "^1.4.0", - "axios-retry": "^4.4.1", - "cheerio": "^1.0.0", - "date-fns": "^2.30.0", - "p-limit": "^6.1.0", - "socks-proxy-agent": "^8.0.2", - "zod": "^3.22.4", }, "devDependencies": { "@types/node": "^20.11.0", @@ -993,10 +976,6 @@ "axios": ["axios@1.10.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw=="], - "axios-rate-limit": ["axios-rate-limit@1.4.0", "", { "dependencies": { "axios": ">=0.18.0" } }, "sha512-uM5PbmSUdSle1I+59Av/wpLuNRobfatIR+FyylSoHcVHT20ohjflNnLMEHZQr7N2QVG/Wlt8jekIPhWwoKtpXQ=="], - - "axios-retry": ["axios-retry@4.5.0", "", { "dependencies": { "is-retry-allowed": "^2.2.0" }, "peerDependencies": { "axios": "0.x || 1.x" } }, "sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ=="], - "b4a": ["b4a@1.6.7", "", {}, "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg=="], "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], @@ -1027,8 +1006,6 @@ "body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="], - "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], - "bowser": ["bowser@2.11.0", "", {}, "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA=="], "bplist-parser": ["bplist-parser@0.2.0", "", { "dependencies": { "big-integer": "^1.6.44" } }, "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw=="], @@ -1077,10 +1054,6 @@ "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - "cheerio": ["cheerio@1.1.0", "", { "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "encoding-sniffer": "^0.2.0", "htmlparser2": "^10.0.0", "parse5": "^7.3.0", "parse5-htmlparser2-tree-adapter": "^7.1.0", "parse5-parser-stream": "^7.1.2", "undici": "^7.10.0", "whatwg-mimetype": "^4.0.0" } }, "sha512-+0hMx9eYhJvWbgpKV9hN7jg0JcwydpopZE4hgi+KvQtByZXPp04NiCWU0LzcAbP63abZckIHkTQaXVF52mX3xQ=="], - - "cheerio-select": ["cheerio-select@2.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", "css-what": "^6.1.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1" } }, "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g=="], - "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], "chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], @@ -1141,10 +1114,6 @@ "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], - "css-select": ["css-select@5.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg=="], - - "css-what": ["css-what@6.1.0", "", {}, "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw=="], - "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], @@ -1157,8 +1126,6 @@ "data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="], - "date-fns": ["date-fns@2.30.0", "", { "dependencies": { "@babel/runtime": "^7.21.0" } }, "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw=="], - "dateformat": ["dateformat@4.6.3", "", {}, "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA=="], "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], @@ -1211,14 +1178,6 @@ "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], - "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], - - "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], - - "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], - - "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], - "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], @@ -1231,11 +1190,9 @@ "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], - "encoding-sniffer": ["encoding-sniffer@0.2.1", "", { "dependencies": { "iconv-lite": "^0.6.3", "whatwg-encoding": "^3.1.1" } }, "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw=="], - "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], - "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], "es-abstract": ["es-abstract@1.24.0", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg=="], @@ -1449,8 +1406,6 @@ "hono": ["hono@4.8.2", "", {}, "sha512-hM+1RIn9PK1I6SiTNS6/y7O1mvg88awYLFEuEtoiMtRyT3SD2iu9pSFgbBXT3b1Ua4IwzvSTLvwO0SEhDxCi4w=="], - "htmlparser2": ["htmlparser2@10.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.1", "entities": "^6.0.0" } }, "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g=="], - "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="], "http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="], @@ -1537,8 +1492,6 @@ "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], - "is-retry-allowed": ["is-retry-allowed@2.2.0", "", {}, "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg=="], - "is-set": ["is-set@2.0.3", "", {}, "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg=="], "is-shared-array-buffer": ["is-shared-array-buffer@1.0.4", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="], @@ -1751,8 +1704,6 @@ "npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="], - "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], - "numeral": ["numeral@2.0.6", "", {}, "sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA=="], "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], @@ -1799,7 +1750,7 @@ "p-cancelable": ["p-cancelable@4.0.1", "", {}, "sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg=="], - "p-limit": ["p-limit@6.2.0", "", { "dependencies": { "yocto-queue": "^1.1.1" } }, "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA=="], + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], @@ -1815,10 +1766,6 @@ "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], - "parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@7.1.0", "", { "dependencies": { "domhandler": "^5.0.3", "parse5": "^7.0.0" } }, "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g=="], - - "parse5-parser-stream": ["parse5-parser-stream@7.1.2", "", { "dependencies": { "parse5": "^7.0.0" } }, "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow=="], - "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], @@ -2269,10 +2216,6 @@ "webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="], - "whatwg-encoding": ["whatwg-encoding@3.1.1", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ=="], - - "whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="], - "whatwg-url": ["whatwg-url@14.2.0", "", { "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" } }, "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw=="], "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], @@ -2309,7 +2252,7 @@ "yauzl": ["yauzl@3.2.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "pend": "~1.2.0" } }, "sha512-Ow9nuGZE+qp1u4JIPvg+uCiUr7xGQWdff7JQSk5VGYTAZMDe2q8lxJ10ygv10qmSj031Ty/6FNJpLO4o1Sgc+w=="], - "yocto-queue": ["yocto-queue@1.2.1", "", {}, "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg=="], + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], "yup": ["yup@1.6.1", "", { "dependencies": { "property-expr": "^2.0.5", "tiny-case": "^1.0.3", "toposort": "^2.0.2", "type-fest": "^2.19.0" } }, "sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA=="], @@ -2425,8 +2368,6 @@ "bl/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], - "cheerio/undici": ["undici@7.10.0", "", {}, "sha512-u5otvFBOBZvmdjWLVW+5DAc9Nkq8f24g0O9oY7qw2JVIF1VocIFoyz9JFkuVOS2j41AufeO0xnlweJ2RLT8nGw=="], - "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "compress-commons/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], @@ -2481,8 +2422,6 @@ "got/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], - "htmlparser2/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], - "is-wsl/is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], "joi/@hapi/hoek": ["@hapi/hoek@9.3.0", "", {}, "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ=="], @@ -2509,10 +2448,6 @@ "os-dns-native/node-addon-api": ["node-addon-api@4.3.0", "", {}, "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ=="], - "p-locate/p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], - - "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], - "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "pg-mem/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], @@ -2783,8 +2718,6 @@ "mongodb-memory-server-core/mongodb/mongodb-connection-string-url": ["mongodb-connection-string-url@2.6.0", "", { "dependencies": { "@types/whatwg-url": "^8.2.1", "whatwg-url": "^11.0.0" } }, "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ=="], - "p-locate/p-limit/yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - "pkg-dir/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], "prebuild-install/tar-fs/tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], diff --git a/check-db-usage.ts b/check-db-usage.ts deleted file mode 100644 index e757592..0000000 --- a/check-db-usage.ts +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bun -/** - * Check Dragonfly database usage to understand which services use which databases - */ - -import Redis from 'ioredis'; - -async function checkDatabaseUsage() { - console.log('🔍 Checking Dragonfly database usage...\n'); - - const redis = new Redis({ - host: process.env.DRAGONFLY_HOST || 'localhost', - port: parseInt(process.env.DRAGONFLY_PORT || '6379'), - password: process.env.DRAGONFLY_PASSWORD || undefined, - lazyConnect: true, - }); - - try { - await redis.connect(); - - // Check databases 0-15 - for (let db = 0; db < 16; db++) { - try { - // Select database - await redis.select(db); - - // Get database size - const dbSize = await redis.dbsize(); - - if (dbSize > 0) { - console.log(`📊 Database ${db}: ${dbSize} keys`); - - // Get sample keys - const keys = await redis.keys('*'); - const sampleKeys = keys.slice(0, 10); - - for (const key of sampleKeys) { - const type = await redis.type(key); - const ttl = await redis.ttl(key); - console.log(` ├─ ${key} (${type}${ttl > 0 ? `, TTL: ${ttl}s` : ttl === -1 ? ', no TTL' : ''})`); - } - - if (keys.length > 10) { - console.log(` └─ ... and ${keys.length - 10} more keys`); - } - console.log(''); - } - } catch (error) { - // Skip databases that don't exist or are inaccessible - } - } - - await redis.disconnect(); - } catch (error) { - console.error('❌ Error:', error); - } -} - -checkDatabaseUsage().catch(console.error); \ No newline at end of file diff --git a/libs/core/di/src/connection-factory.ts b/libs/core/di/src/connection-factory.ts index e769719..0b98c68 100644 --- a/libs/core/di/src/connection-factory.ts +++ b/libs/core/di/src/connection-factory.ts @@ -208,11 +208,14 @@ export class ConnectionFactory implements IConnectionFactory { const manager = QueueManager.initialize({ redis: poolConfig.config as any, defaultQueueOptions: { + workers: 2, // Default number of workers per queue + concurrency: 1, // Jobs processed concurrently per worker defaultJobOptions: { removeOnComplete: 100, removeOnFail: 50, }, }, + delayWorkerStart: false, // Start workers immediately when queues are created }); const pool: ConnectionPool = { diff --git a/libs/core/handlers/package.json b/libs/core/handlers/package.json index 9b9db79..6f8551e 100644 --- a/libs/core/handlers/package.json +++ b/libs/core/handlers/package.json @@ -12,6 +12,7 @@ "dependencies": { "@stock-bot/config": "workspace:*", "@stock-bot/logger": "workspace:*", + "@stock-bot/types": "workspace:*", "@stock-bot/di": "workspace:*" }, "devDependencies": { diff --git a/libs/core/handlers/src/index.ts b/libs/core/handlers/src/index.ts index 752d78d..cd63e6b 100644 --- a/libs/core/handlers/src/index.ts +++ b/libs/core/handlers/src/index.ts @@ -1,8 +1,8 @@ // Base handler classes export { BaseHandler, ScheduledHandler } from './base/BaseHandler'; -// Handler registry -export { handlerRegistry } from './registry/HandlerRegistry'; +// Handler registry (re-exported from types to avoid circular deps) +export { handlerRegistry } from '@stock-bot/types'; // Types export type { diff --git a/libs/core/handlers/src/types/types.ts b/libs/core/handlers/src/types/types.ts index 07e3761..a547ecd 100644 --- a/libs/core/handlers/src/types/types.ts +++ b/libs/core/handlers/src/types/types.ts @@ -1,73 +1,14 @@ -import type { ServiceContainer } from '@stock-bot/di'; +// Re-export all handler types from the shared types package +export type { + ExecutionContext, + HandlerConfig, + HandlerConfigWithSchedule, + HandlerMetadata, + IHandler, + JobHandler, + OperationMetadata, + ScheduledJob, + TypedJobHandler, +} from '@stock-bot/types'; -// Simple execution context - mostly queue for now -export interface ExecutionContext { - type: 'queue'; // | 'event' - commented for future - serviceContainer: ServiceContainer; - metadata: { - source?: string; - jobId?: string; - attempts?: number; - timestamp: number; - [key: string]: unknown; - }; -} - -// Simple handler interface -export interface IHandler { - execute(operation: string, input: unknown, context: ExecutionContext): Promise; -} - -// Job handler type for queue operations -export interface JobHandler { - (payload: TPayload): Promise; -} - -// Scheduled job configuration -export interface ScheduledJob { - type: string; - operation: string; - payload?: T; - cronPattern: string; - priority?: number; - description?: string; - immediately?: boolean; - delay?: number; -} - -// Handler configuration -export interface HandlerConfig { - [operation: string]: JobHandler; -} - -// Handler configuration with schedule -export interface HandlerConfigWithSchedule { - name: string; - operations: Record; - scheduledJobs?: ScheduledJob[]; -} - -// Type-safe wrapper for creating job handlers -export type TypedJobHandler = (payload: TPayload) => Promise; - -// Helper to create type-safe job handlers -export function createJobHandler( - handler: TypedJobHandler -): JobHandler { - return async (payload: unknown): Promise => { - return handler(payload as TPayload); - }; -} - -// Handler metadata for decorators (future) -export interface HandlerMetadata { - name: string; - operations: OperationMetadata[]; -} - -export interface OperationMetadata { - name: string; - schedules?: string[]; - // eventListeners?: string[]; // Future - // eventPublishers?: string[]; // Future -} \ No newline at end of file +export { createJobHandler } from '@stock-bot/types'; \ No newline at end of file diff --git a/libs/core/types/src/handler-registry.ts b/libs/core/types/src/handler-registry.ts new file mode 100644 index 0000000..cb230ed --- /dev/null +++ b/libs/core/types/src/handler-registry.ts @@ -0,0 +1,111 @@ +/** + * Handler Registry - Lightweight registry for queue handlers + * Moved here to avoid circular dependencies between handlers and queue + */ + +import type { JobHandler, HandlerConfig, HandlerConfigWithSchedule, ScheduledJob } from './handlers'; + +class HandlerRegistry { + private handlers = new Map(); + private handlerSchedules = new Map(); + + /** + * Register a handler with its operations (simple config) + */ + register(handlerName: string, config: HandlerConfig): void { + console.log(`Registering handler: ${handlerName}`, { + operations: Object.keys(config), + }); + + this.handlers.set(handlerName, config); + } + + /** + * Register a handler with scheduled jobs (enhanced config) + */ + registerWithSchedule(config: HandlerConfigWithSchedule): void { + console.log(`Registering handler with schedule: ${config.name}`, { + operations: Object.keys(config.operations), + scheduledJobs: config.scheduledJobs?.length || 0, + }); + + this.handlers.set(config.name, config.operations); + + if (config.scheduledJobs && config.scheduledJobs.length > 0) { + this.handlerSchedules.set(config.name, config.scheduledJobs); + } + } + + /** + * Get a specific handler's configuration + */ + getHandler(handlerName: string): HandlerConfig | undefined { + return this.handlers.get(handlerName); + } + + /** + * Get all registered handlers + */ + getAllHandlers(): Map { + return new Map(this.handlers); + } + + /** + * Get scheduled jobs for a handler + */ + getScheduledJobs(handlerName: string): ScheduledJob[] { + return this.handlerSchedules.get(handlerName) || []; + } + + /** + * Get all handlers with their scheduled jobs + */ + getAllHandlersWithSchedule(): Map { + const result = new Map(); + + for (const [name, operations] of this.handlers) { + result.set(name, { + operations, + scheduledJobs: this.handlerSchedules.get(name) || [] + }); + } + + return result; + } + + /** + * Get a specific operation from a handler + */ + getOperation(handlerName: string, operationName: string): JobHandler | undefined { + const handler = this.handlers.get(handlerName); + if (!handler) { + return undefined; + } + return handler[operationName]; + } + + /** + * Check if a handler is registered + */ + hasHandler(handlerName: string): boolean { + return this.handlers.has(handlerName); + } + + /** + * Get list of all registered handler names + */ + getHandlerNames(): string[] { + return Array.from(this.handlers.keys()); + } + + /** + * Clear all registrations (useful for testing) + */ + clear(): void { + this.handlers.clear(); + this.handlerSchedules.clear(); + } +} + +// Export singleton instance +export const handlerRegistry = new HandlerRegistry(); \ No newline at end of file diff --git a/libs/core/types/src/handlers.ts b/libs/core/types/src/handlers.ts new file mode 100644 index 0000000..f524b99 --- /dev/null +++ b/libs/core/types/src/handlers.ts @@ -0,0 +1,83 @@ +/** + * Handler and Queue Types + * Shared types for handler system and queue operations + */ + +// Simple execution context - mostly queue for now +export interface ExecutionContext { + type: 'queue'; // | 'event' - commented for future + serviceContainer?: any; // Will be typed properly when needed + metadata: { + source?: string; + jobId?: string; + attempts?: number; + timestamp: number; + [key: string]: unknown; + }; +} + +// Simple handler interface +export interface IHandler { + execute(operation: string, input: unknown, context: ExecutionContext): Promise; +} + +// Job handler type for queue operations +export interface JobHandler { + (payload: TPayload): Promise; +} + +// Type-safe wrapper for creating job handlers +export type TypedJobHandler = (payload: TPayload) => Promise; + +// Scheduled job configuration +export interface ScheduledJob { + type: string; + operation: string; + payload?: T; + cronPattern: string; + priority?: number; + description?: string; + immediately?: boolean; + delay?: number; +} + +// Handler configuration +export interface HandlerConfig { + [operation: string]: JobHandler; +} + +// Handler configuration with schedule +export interface HandlerConfigWithSchedule { + name: string; + operations: Record; + scheduledJobs?: ScheduledJob[]; +} + +// Handler metadata for registry +export interface HandlerMetadata { + name: string; + version?: string; + description?: string; + operations: string[]; + scheduledJobs?: ScheduledJob[]; +} + +// Operation metadata for decorators +export interface OperationMetadata { + name: string; + schedules?: string[]; + operation?: string; + description?: string; + validation?: (input: unknown) => boolean; +} + +/** + * Create a typed job handler with validation + */ +export function createJobHandler( + handler: TypedJobHandler +): JobHandler { + return async (payload: unknown): Promise => { + return handler(payload as TPayload); + }; +} \ No newline at end of file diff --git a/libs/core/types/src/index.ts b/libs/core/types/src/index.ts index e66c07e..237fc0a 100644 --- a/libs/core/types/src/index.ts +++ b/libs/core/types/src/index.ts @@ -47,3 +47,20 @@ export type { BacktestResults } from './backtesting'; // Export helper types export type { HasClose, HasOHLC, HasTimestamp, HasVolume } from './helpers'; + +// Export handler types +export type { + ExecutionContext, + HandlerConfig, + HandlerConfigWithSchedule, + HandlerMetadata, + IHandler, + JobHandler, + OperationMetadata, + ScheduledJob, + TypedJobHandler, +} from './handlers'; +export { createJobHandler } from './handlers'; + +// Export handler registry +export { handlerRegistry } from './handler-registry'; diff --git a/libs/data/mongodb/src/client.ts b/libs/data/mongodb/src/client.ts index 6fa8947..2911c7f 100644 --- a/libs/data/mongodb/src/client.ts +++ b/libs/data/mongodb/src/client.ts @@ -307,6 +307,14 @@ export class MongoDBClient { return db.collection(name); } + /** + * Get a collection (interface compatibility method) + * This method provides compatibility with the IMongoDBClient interface + */ + collection(name: string, database?: string): Collection { + return this.getCollection(name, database); + } + /** * Simple insert operation */ diff --git a/libs/services/queue/package.json b/libs/services/queue/package.json index 0a49952..5f10b43 100644 --- a/libs/services/queue/package.json +++ b/libs/services/queue/package.json @@ -14,7 +14,6 @@ "ioredis": "^5.3.0", "rate-limiter-flexible": "^3.0.0", "@stock-bot/cache": "*", - "@stock-bot/handlers": "*", "@stock-bot/logger": "*", "@stock-bot/types": "*" }, diff --git a/libs/services/queue/src/index.ts b/libs/services/queue/src/index.ts index 992b1ab..f6224aa 100644 --- a/libs/services/queue/src/index.ts +++ b/libs/services/queue/src/index.ts @@ -3,8 +3,8 @@ export { Queue, type QueueWorkerConfig } from './queue'; export { QueueManager } from './queue-manager'; export { createJobHandler } from './types'; -// Re-export handler registry from new location -export { handlerRegistry } from '@stock-bot/handlers'; +// Re-export handler registry from types package +export { handlerRegistry } from '@stock-bot/types'; // Batch processing export { processBatchJob, processItems } from './batch-processor'; diff --git a/libs/services/queue/src/queue-manager.ts b/libs/services/queue/src/queue-manager.ts index ee2ac14..abdbce1 100644 --- a/libs/services/queue/src/queue-manager.ts +++ b/libs/services/queue/src/queue-manager.ts @@ -442,7 +442,7 @@ export class QueueManager { */ startAllWorkers(): void { if (!this.config.delayWorkerStart) { - logger.warn('startAllWorkers() called but delayWorkerStart is not enabled'); + logger.info('startAllWorkers() called but workers already started automatically (delayWorkerStart is false)'); return; } diff --git a/libs/services/queue/src/queue.ts b/libs/services/queue/src/queue.ts index 3d29cf5..e77b30b 100644 --- a/libs/services/queue/src/queue.ts +++ b/libs/services/queue/src/queue.ts @@ -1,6 +1,6 @@ import { Queue as BullQueue, QueueEvents, Worker, type Job } from 'bullmq'; import { getLogger } from '@stock-bot/logger'; -import { handlerRegistry } from '@stock-bot/handlers'; +import { handlerRegistry } from '@stock-bot/types'; import type { JobData, JobOptions, QueueStats, RedisConfig } from './types'; import { getRedisConnection } from './utils'; @@ -309,7 +309,7 @@ export class Queue { try { // Look up handler in registry - const jobHandler = handlerRegistry.getHandler(handler, operation); + const jobHandler = handlerRegistry.getOperation(handler, operation); if (!jobHandler) { throw new Error(`No handler found for ${handler}:${operation}`); diff --git a/libs/services/queue/src/types.ts b/libs/services/queue/src/types.ts index 83c0b1b..417091a 100644 --- a/libs/services/queue/src/types.ts +++ b/libs/services/queue/src/types.ts @@ -1,11 +1,11 @@ -// Re-export handler types from new location +// Re-export handler types from shared types package export type { JobHandler, TypedJobHandler, HandlerConfig, HandlerConfigWithSchedule, ScheduledJob, -} from '@stock-bot/handlers'; +} from '@stock-bot/types'; // Types for queue operations export interface JobData { @@ -110,8 +110,8 @@ export interface QueueConfig extends QueueManagerConfig { enableMetrics?: boolean; } -// Re-export createJobHandler from handlers library -export { createJobHandler } from '@stock-bot/handlers'; +// Re-export createJobHandler from shared types package +export { createJobHandler } from '@stock-bot/types'; export interface BatchJobData { payloadKey: string; diff --git a/scripts/build-libs.sh b/scripts/build-libs.sh index ddf124d..b9f676b 100755 --- a/scripts/build-libs.sh +++ b/scripts/build-libs.sh @@ -35,7 +35,6 @@ libs=( "core/types" # Base types - no dependencies "core/config" # Configuration - depends on types "core/logger" # Logging utilities - depends on types - "core/handlers" # Handler infrastructure - depends on core libs # Data access libraries "data/cache" # Cache - depends on core libs @@ -48,11 +47,17 @@ libs=( "services/event-bus" # Event bus - depends on core libs "services/shutdown" # Shutdown - depends on core libs "services/browser" # Browser - depends on core libs - "services/queue" # Queue - depends on core libs, cache, and handlers + "services/queue" # Queue - depends on core libs and cache - # Utils and DI last - depend on many other libs + # Utils "utils" # Utilities - depends on many libs + + # DI - dependency injection library "core/di" # Dependency injection - depends on data and service libs + "core/handlers" # Handlers - depends on core libs and utils + + # Note: core/handlers is not included in lib build chain since no libs depend on it + # It's built separately when needed by applications ) # Build each library in order