UNPKG

@mwcp/kmore

Version:

midway component for knex, supports declarative transaction and OpenTelemetry

306 lines 12.9 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; /* eslint-disable max-lines-per-function */ import assert from 'node:assert'; import { App, ApplicationContext, DataSourceManager, Init, Inject, Logger as _Logger, Singleton, } from '@midwayjs/core'; import { SpanKind, Trace, TraceInit } from '@mwcp/otel'; import { MConfig, getWebContext } from '@mwcp/share'; // eslint-disable-next-line import/no-extraneous-dependencies import { context } from '@opentelemetry/api'; import { KmoreFactory, getCurrentTime, } from 'kmore'; import { DbEvent } from './db-event.js'; import { DbHook } from './db-hook/index.db-hook.js'; import { eventNeedTrace, genCommonAttr } from './trace.helper.js'; import { TrxStatusService } from './trx-status.service.js'; import { ConfigKey, KmoreAttrNames } from './types.js'; let DbManager = class DbManager extends DataSourceManager { sourceConfig; app; applicationContext; logger; baseDir; dbEvent; dbHook; trxStatusSvc; async init() { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!this?.sourceConfig?.dataSource) { this.logger.info('dataSourceConfig is not defined'); return; } await this.initDataSource(this.sourceConfig, ''); } getDbConfigByDbId(dbId) { assert(dbId); const dbConfig = this.sourceConfig.dataSource[dbId]; return dbConfig; } getWebContext() { return getWebContext(this.applicationContext); } getWebContextThenApp() { 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; } } getName() { return 'dbManager'; } // #region checkConnected async checkConnected(dataSource) { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!dataSource) { return false; } const { dbh, config } = dataSource; try { const time = await getCurrentTime(dbh, config.client); return !!time; } catch (ex) { this.logger.error('[KmoreDbSourceManager]: checkConnected(). error ignored', ex); } return false; } // #region createDataSource /** * 创建单个实例 */ async createDataSource(config, dataSourceName) { const inst = await this._createDataSource(config, dataSourceName); assert(inst, `createDataSource() failed: ${dataSourceName}`); this.dbHook.createProxy(inst); return inst; } // #region getDataSource getDataSource(dataSourceName) { const db = super.getDataSource(dataSourceName); assert(db, `[${ConfigKey.componentName}] getDataSource() db source empty: "${dataSourceName}"`); assert(db.dbId === dataSourceName, `[${ConfigKey.componentName}] getDataSource() db source id not match: "${dataSourceName}"`); return db; } // #region destroyDataSource async destroyDataSource(dataSource) { if (await this.checkConnected(dataSource)) { try { await dataSource.destroy(); this.dataSource.delete(dataSource.dbId); this.trxStatusSvc.unregisterDbInstance(dataSource.dbId); } catch (ex) { this.logger.error(`Destroy knex connection failed with identifier: "${dataSource.instanceId.toString()}" : \n${ex.message}`); } } } /** * 创建单个实例 */ async _createDataSource(config, dataSourceName) { const globalEventCbs = { start: (event, kmore) => { if (kmore.enableTrace) { let activeTraceCtx; const traceScope = this.dbEvent.retrieveTraceScope(kmore, event.kmoreQueryId, event.queryBuilder); const activeRoot = this.trxStatusSvc.getTraceContextByScope(traceScope); if (activeRoot) { activeTraceCtx = activeRoot; } else { const trx = kmore.getTrxByQueryId(event.kmoreQueryId); activeTraceCtx = trx ? kmore.trx2TraceContextMap.get(trx) : void 0; } if (!activeTraceCtx) { activeTraceCtx = context.active(); } context.with(activeTraceCtx, () => { this.dbEvent.onStart({ dataSourceName, dbConfig: config, event, kmore }); }); return; } this.dbEvent.onStart({ dataSourceName, dbConfig: config, event, kmore }); }, query: (event, kmore) => { if (kmore.enableTrace) { let activeTraceCtx = this.trxStatusSvc.getTraceContextByScope(event.kmoreQueryId); if (!activeTraceCtx) { const traceScope = this.dbEvent.retrieveTraceScope(kmore, event.kmoreQueryId, event.queryBuilder); const active = this.trxStatusSvc.getTraceContextByScope(traceScope); if (active) { activeTraceCtx = active; } else { const trx = kmore.getTrxByQueryId(event.kmoreQueryId); activeTraceCtx = trx ? kmore.trx2TraceContextMap.get(trx) : void 0; } } context.with(activeTraceCtx ?? context.active(), () => { this.dbEvent.onQuery({ dataSourceName, dbConfig: config, event, kmore }); }); return; } this.dbEvent.onQuery({ dataSourceName, dbConfig: config, event, kmore }); }, queryResponse: (event, kmore) => { if (kmore.enableTrace) { let activeTraceCtx = this.trxStatusSvc.getTraceContextByScope(event.kmoreQueryId); if (!activeTraceCtx) { const traceScope = this.dbEvent.retrieveTraceScope(kmore, event.kmoreQueryId, event.queryBuilder); const active = this.trxStatusSvc.getTraceContextByScope(traceScope); if (active) { activeTraceCtx = active; } else { const trx = kmore.getTrxByQueryId(event.kmoreQueryId); activeTraceCtx = trx ? kmore.trx2TraceContextMap.get(trx) : void 0; } } context.with(activeTraceCtx ?? context.active(), () => { this.dbEvent.onResp({ dataSourceName, dbConfig: config, event, kmore }); }); return; } this.dbEvent.onResp({ dataSourceName, dbConfig: config, event, kmore }); }, queryError: (event, kmore) => { if (kmore.enableTrace) { let activeTraceCtx = this.trxStatusSvc.getTraceContextByScope(event.kmoreQueryId); if (!activeTraceCtx) { const traceScope = this.dbEvent.retrieveTraceScope(kmore, event.kmoreQueryId, event.queryBuilder); const active = this.trxStatusSvc.getTraceContextByScope(traceScope); if (active) { activeTraceCtx = active; } else { const trx = kmore.getTrxByQueryId(event.kmoreQueryId); activeTraceCtx = trx ? kmore.trx2TraceContextMap.get(trx) : void 0; } } return context.with(activeTraceCtx ?? context.active(), () => { return this.dbEvent.onError({ dataSourceName, dbConfig: config, event, kmore }); }); } return this.dbEvent.onError({ dataSourceName, dbConfig: config, event, kmore }); }, }; const opts = { dbId: dataSourceName, ...config, eventCallbacks: globalEventCbs, }; const inst = KmoreFactory(opts); // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!this.sourceConfig.dataSource[dataSourceName]) { this.sourceConfig.dataSource[dataSourceName] = config; } return inst; } }; __decorate([ MConfig(ConfigKey.config), __metadata("design:type", Object) ], DbManager.prototype, "sourceConfig", void 0); __decorate([ App(), __metadata("design:type", Object) ], DbManager.prototype, "app", void 0); __decorate([ ApplicationContext(), __metadata("design:type", Object) ], DbManager.prototype, "applicationContext", void 0); __decorate([ _Logger(), __metadata("design:type", Object) ], DbManager.prototype, "logger", void 0); __decorate([ Inject(), __metadata("design:type", String) ], DbManager.prototype, "baseDir", void 0); __decorate([ Inject(), __metadata("design:type", DbEvent) ], DbManager.prototype, "dbEvent", void 0); __decorate([ Inject(), __metadata("design:type", DbHook) ], DbManager.prototype, "dbHook", void 0); __decorate([ Inject(), __metadata("design:type", TrxStatusService) ], DbManager.prototype, "trxStatusSvc", void 0); __decorate([ TraceInit(`INIT ${ConfigKey.namespace}.DbSourceManager.init()`), Init(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], DbManager.prototype, "init", null); __decorate([ Trace({ spanName: () => 'DbManager getDataSource', startActiveSpan: false, kind: SpanKind.INTERNAL, before([dataSourceName]) { const dbConfig = this.getDbConfigByDbId(dataSourceName); if (dbConfig && !eventNeedTrace(KmoreAttrNames.getDataSourceStart, dbConfig)) { return; } const attrs = { dbId: dataSourceName, }; const events = genCommonAttr(KmoreAttrNames.getDataSourceStart); return { attrs, events }; }, after([dataSourceName]) { const dbConfig = this.getDbConfigByDbId(dataSourceName); if (dbConfig && !eventNeedTrace(KmoreAttrNames.getDataSourceStart, dbConfig)) { return; } const events = genCommonAttr(KmoreAttrNames.getDataSourceEnd); return { events }; }, }), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", Function) ], DbManager.prototype, "getDataSource", null); __decorate([ TraceInit({ spanName: ([, dataSourceName]) => `INIT ${ConfigKey.namespace}.DbSourceManager._createDataSource():${dataSourceName}`, before: (args) => { if (!args[0].traceInitConnection) { return; } const config = { ...args[0] }; delete config.dict; delete config.eventCallbacks; const events = { event: 'createDataSource.before', config: JSON.stringify(config), dataSourceName: args[1], }; return { events }; }, }), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, String]), __metadata("design:returntype", Promise) ], DbManager.prototype, "_createDataSource", null); DbManager = __decorate([ Singleton() ], DbManager); export { DbManager }; //# sourceMappingURL=db-source-manager.js.map