UNPKG

@mwcp/kmore

Version:

midway component for knex, supports declarative transaction and OpenTelemetry

205 lines (164 loc) 6.88 kB
import assert from 'node:assert' import { App, ApplicationContext, IMidwayContainer, Inject, Singleton, } from '@midwayjs/core' import { TraceLog, TraceScopeType, TraceService } from '@mwcp/otel' import { Application, Context, MConfig, getWebContext } from '@mwcp/share' import type { BuilderHookOptions, BuilderTransactingHookOptions, Kmore, KmoreTransaction, ResponseHookOptions, } from 'kmore' import { eventNeedTrace, genCommonAttr } from '../trace.helper.js' import { TrxStatusService } from '../trx-status.service.js' import { ConfigKey, DbConfig, KmoreAttrNames, KmoreSourceConfig } from '../types.js' @Singleton() export class DbHookBuilder<SourceName extends string = string> { @MConfig(ConfigKey.config) private readonly sourceConfig: KmoreSourceConfig<SourceName> @App() readonly app: Application @ApplicationContext() readonly applicationContext: IMidwayContainer @Inject() readonly appDir: string @Inject() readonly baseDir: string @Inject() readonly trxStatusSvc: TrxStatusService @Inject() readonly traceService: TraceService // #region builderPreHooks builderPreHooks(options: BuilderHookOptions): void { this.builderPrePropagating(options) } // #region builderPostHooks async builderPostHook(options: BuilderHookOptions): Promise<void> { await this.builderPostPropagating(options) } protected builderPrePropagating(options: BuilderHookOptions): void { const { kmore, builder } = options if (! builder.scope) { builder.scope = this.getWebContext() } if (! builder.scope) { builder.scope = this.app } if (builder.trxPropagated) { return } /* Call stack in bindBuilderPropagationData(): 1 - TrxStatusService.bindBuilderPropagationData(trx-status.service.ts: 389) 2 - DbSourceManager.builderPrePropagating(db- source-manager.ts: 377) 3 - DbSourceManager.builderPreProcessor(db-source-manager.ts: 378) 4 - <anonymous>(builder.index.js: 67) 5 - extRefTableFnProperty(builder.index.js: 64) 6 - tb_user(builder.index.js: 28) 7 - UserRepo6.getUsers(70c.cache.repo.ts: 78) <-- call from here 6+1 8 - Clz.<computed>(aspectService.js: 92) */ /* 1 - TrxStatusService.bindBuilderPropagationData (trx-status.service.ts:318) 2 - DbSourceManager.builderPrePropagating (db-source-manager.ts:404) 3 - DbSourceManager.builderPreProcessor (db-source-manager.ts:377) 4 - <anonymous> (builder.index.js:62) 5 - createQueryBuilder (builder.index.js:59) 6 - tb_user (builder.index.js:27) 7 - TrxRepo._update (101/101r.middle-trx-auto-action.repo.ts:46) <-- call from here 6+1 8 - TrxRepo.commit (101/101r.middle-trx-auto-action.repo.ts:33) */ /* 1 - TrxStatusService.bindBuilderPropagationData(src\lib\trx-status.service.ts: 342) 2 - DbHookBuilder.builderPrePropagating(src\lib\db-hook\db-hook.builder.ts: 87) 3 - DbHookBuilder.builderPreHooks(src\lib\db-hook\db-hook.builder.ts: 44) 4 - <anonymous>(kmore\dist\lib\builder\builder.index.js: 57) 5 - createQueryBuilder(kmore\dist\lib\builder\builder.index.js: 55) 6 - tb_user(kmore\dist\lib\builder\builder.index.js: 25) 7 - TransactionalSimpleRepo.getUserOne(test\fixtures\base-app\src\transactional\30\30r.transactional - simple.repo.ts: 51) 8 - Clz.<computed>(kmore\node_modules\@midwayjs\core\dist\service\aspectService.js: 92) 9 - process.processTicksAndRejections(<node_internals> /internal/process / task_queues: 105) 10 - await(未知源: 0) 11 - user(test\fixtures\base - app\src\transactional\30\30r.transactional - simple.repo.ts: 33) */ this.trxStatusSvc.bindBuilderPropagationData(kmore.dbId, builder, 5) } protected async builderPostPropagating(options: BuilderHookOptions): Promise<void> { const { builder } = options if (! builder.scope) { builder.scope = this.getWebContext() } if (builder.trxPropagated) { return } await this.trxStatusSvc.propagating({ builder, db: options.kmore, }) } // #region builderResultPreHook async builderResultPreHook(options: ResponseHookOptions): Promise<void> { if (options.kmoreTrxId && options.trxPropagated && options.trxPropagateOptions) { const { builder, rowLockLevel } = options if (rowLockLevel) { // @FIXME // this.trxStatusSvc.updateBuilderSpanRowlockLevelTag(kmoreQueryId, rowLockLevel) void builder } // const { className, funcName } = options.trxPropagateOptions // const callerKey = genCallerKey(className, funcName) // assert(callerKey, 'callerKey is empty') // const tkey = this.trxStatusSvc.retrieveUniqueTopCallerKey(callerKey) } } // #region builderTransactingPostHook @TraceLog<DbHookBuilder['builderTransactingPostHook']>({ after([options]) { // options.dbConfig not exist at before() const dbConfig = this.getDbConfigByDbId(options.kmore.dbId) if (dbConfig && ! eventNeedTrace(KmoreAttrNames.BuilderTransacting, dbConfig)) { return } const { builder } = options // @ts-expect-error builder._method // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment let method: string = builder._method ?? 'unknown' if (method === 'del') { method = 'delete' } // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access const table: string = builder._single?.table ?? '', const events = genCommonAttr(KmoreAttrNames.BuilderTransacting, { kmoreQueryId: builder.kmoreQueryId.toString(), method, table, }) return { events } }, }) builderTransactingPostHook(this: DbHookBuilder, options: BuilderTransactingHookOptions): void { void options } protected getTrxTraceScopeByQueryId(db: Kmore, queryId: symbol): TraceScopeType | undefined { const trx = db.getTrxByQueryId(queryId) return trx?.kmoreTrxId } protected getDbConfigByDbId(dbId: SourceName): DbConfig | undefined { assert(dbId) const dbConfig = this.sourceConfig.dataSource[dbId] return dbConfig } protected getWebContext(): Context | undefined { return getWebContext(this.applicationContext) } protected getWebContextThenApp(): Context | Application { try { const webContext = getWebContext(this.applicationContext) assert(webContext, 'getActiveContext() webContext should not be null, maybe this calling is not in a request context') return webContext } catch (ex) { console.warn('getWebContextThenApp() failed', ex) return this.app } } protected getTraceScopeByTrx(transaction: KmoreTransaction): TraceScopeType { return transaction.kmoreTrxId } }