Skip to content

Commit

Permalink
feat: up
Browse files Browse the repository at this point in the history
  • Loading branch information
waitingsong committed Apr 22, 2024
1 parent 8487dd3 commit 5f26166
Show file tree
Hide file tree
Showing 12 changed files with 156 additions and 253 deletions.
6 changes: 3 additions & 3 deletions packages/midway-component-kmore/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@
},
"license": "MIT",
"dependencies": {
"@mwcp/cache": "^26.0.0",
"@mwcp/otel": "^26.0.0",
"@mwcp/share": "^26.0.0",
"@mwcp/otel": "^26.2.0",
"@mwcp/share": "^26.2.0",
"@waiting/shared-core": "^23.6.1",
"kmore": "^59.5.6",
"knex": "^3.1.0"
},
"devDependencies": {
"@mwcp/cache": "^26.2.0",
"kmore-cli": "^59.5.6",
"kmore-types": "^59.5.6"
},
Expand Down
21 changes: 0 additions & 21 deletions packages/midway-component-kmore/src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,14 @@ import {
Application,
IMidwayContainer,
MConfig,
RegisterDecoratorHandlerParam,
registerDecoratorHandler,
registerMiddleware,
deleteRouter,
} from '@mwcp/share'
import { sleep } from '@waiting/shared-core'


import * as DefaultConfig from './config/config.default.js'
import * as LocalConfig from './config/config.local.js'
import * as UnittestConfig from './config/config.unittest.js'
import {
METHOD_KEY_Transactional,
genDecoratorExecutorOptions,
transactionalDecoratorExecutor,
} from './decorator/decorator.helper.js'
import { useComponents } from './imports.js'
import { DbSourceManager } from './lib/db-source-manager.js'
import { Config, ConfigKey, KmorePropagationConfig, KmoreSourceConfig } from './lib/index.js'
Expand Down Expand Up @@ -86,19 +78,6 @@ export class AutoConfiguration implements ILifeCycle {

// 全局db处理中间件,请求结束时回滚/提交所有本次请求未提交事务
registerMiddleware(this.app, KmoreMiddleware)

const optsCacheable: RegisterDecoratorHandlerParam = {
decoratorKey: METHOD_KEY_Transactional,
decoratorService: this.decoratorService,
fnDecoratorExecutorAsync: transactionalDecoratorExecutor,
fnDecoratorExecutorSync: 'bypass',
fnGenDecoratorExecutorParam: genDecoratorExecutorOptions,
}
const aroundFactoryOptions = {
webApp: this.app,
config: this.propagationConfig,
}
registerDecoratorHandler(optsCacheable, aroundFactoryOptions)
}

@TraceInit({ namespace: ConfigKey.namespace })
Expand Down
105 changes: 2 additions & 103 deletions packages/midway-component-kmore/src/decorator/index.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,105 +1,4 @@
import { assert } from 'console'

import {
CacheableArgs,
METHOD_KEY_CacheEvict,
METHOD_KEY_CachePut,
METHOD_KEY_Cacheable,
cacheableClassIgnoreIfMethodDecoratorKeys,
cacheableMethodIgnoreIfMethodDecoratorKeys,
} from '@mwcp/cache'
import {
CustomDecoratorFactoryParam,
customDecoratorFactory,
regCustomDecorator,
} from '@mwcp/share'

import {
MethodType,
TransactionalArgs,
TRX_CLASS_KEY,
METHOD_KEY_Transactional,
} from './decorator.helper.js'


export {
classDecoratorKeyMap,
methodDecoratorKeyMap,
} from './decorator.helper.js'

export {
TransactionalArgs as DecoratorArgs,
TRX_CLASS_KEY,
METHOD_KEY_Transactional,
METHOD_KEY_Transactional as TRX_METHOD_KEY,
}


/**
* 声明式事务装饰器
* Declarative Transactional Decorator
* @description default config can be set via `KmorePropagationConfig`
* in `src/config/config.{default|prod|local}.ts`
*/
export function Transactional<M extends MethodType | undefined = undefined>(
/**
* @default {@link Propagation.REQUIRED}
*/
propagationType?: TransactionalArgs['propagationType'],
propagationOptions?: TransactionalArgs['propagationOptions'],
cacheOptions: TransactionalArgs<M>['cacheOptions'] = false,
) {

const options: Partial<TransactionalArgs<M>> = {
// propagationType,
// propagationOptions,
// cacheOptions,
}
// !!
if (propagationType) {
options.propagationType = propagationType
}
if (propagationOptions) {
options.propagationOptions = propagationOptions
}
if (cacheOptions) {
options.cacheOptions = cacheOptions
}

const opts: CustomDecoratorFactoryParam<TransactionalArgs<M>> = {
decoratorKey: METHOD_KEY_Transactional,
decoratorArgs: options,
enableClassDecorator: true,
}
if (cacheOptions) {
let dkey = ''
switch (cacheOptions.op) {
case 'Cacheable':
dkey = METHOD_KEY_Cacheable
break

case 'CacheEvict':
dkey = METHOD_KEY_CacheEvict
break

case 'CachePut':
dkey = METHOD_KEY_CachePut
break
}
assert(dkey, `invalid cacheOptions.op: ${cacheOptions.op}`)

opts.before = (target, propertyName, descriptor) => {
const opts2: CustomDecoratorFactoryParam<CacheableArgs<M>> = {
decoratorKey: dkey,
decoratorArgs: cacheOptions,
enableClassDecorator: false,
classIgnoreIfMethodDecoratorKeys: cacheableClassIgnoreIfMethodDecoratorKeys,
methodIgnoreIfMethodDecoratorKeys: cacheableMethodIgnoreIfMethodDecoratorKeys,
}
regCustomDecorator(target, propertyName, descriptor, opts2)
}
}

return customDecoratorFactory<TransactionalArgs<M>>(opts)
}
export * from './transactional.js'
export * from './transactional.handler.js'

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Singleton } from '@midwayjs/core'
import { MConfig, DecoratorExecutorParamBase, DecoratorHandlerBase } from '@mwcp/share'

import { ConfigKey, KmorePropagationConfig } from '##/lib/types.js'

import { decoratorExecutor, genDecoratorExecutorOptionsAsync } from './transactional.helper.js'
import { DecoratorExecutorOptions, GenDecoratorExecutorOptionsExt } from './transactional.types.js'


@Singleton()
export class DecoratorHandlerTransactional extends DecoratorHandlerBase {
@MConfig(ConfigKey.propagationConfig) protected readonly propagationConfig: KmorePropagationConfig

override async genExecutorParamAsync(options: DecoratorExecutorParamBase): Promise<DecoratorExecutorOptions> {
const optsExt: GenDecoratorExecutorOptionsExt = {
propagationConfig: this.propagationConfig,
}
const ret = genDecoratorExecutorOptionsAsync(options, optsExt)
return ret
}

override async executorAsync(options: DecoratorExecutorOptions) {
return decoratorExecutor(options)
}
}

Original file line number Diff line number Diff line change
@@ -1,135 +1,64 @@
import assert from 'assert'

import type {
CacheableArgs,
CacheEvictArgs,
} from '@mwcp/cache'
import {
Context as WebContext,
DecoratorExecutorParamBase,
DecoratorMetaDataPayload,
DecoratorMetaData,
deepmerge,
} from '@mwcp/share'
import { DecoratorExecutorParamBase, DecoratorMetaDataPayload, deepmerge } from '@mwcp/share'
import { sleep } from '@waiting/shared-core'
import { PropagationType } from 'kmore'

import { initTransactionalOptions } from '##/lib/config.js'
import { CallerKey, RegisterTrxPropagateOptions } from '##/lib/propagation/trx-status.base.js'
import { genCallerKey } from '##/lib/propagation/trx-status.helper.js'
import { TrxStatusService } from '##/lib/trx-status.service.js'
import { ConfigKey, KmorePropagationConfig, Msg, TransactionalOptions } from '##/lib/types.js'


export const TRX_CLASS_KEY = 'decorator:kmore_trxnal_class_decorator_key'
export const METHOD_KEY_Transactional = 'decorator:kmore_trxnal_decorator_key'
export const classDecoratorKeyMap = new Map([[TRX_CLASS_KEY, 'Transactional']])
export const methodDecoratorKeyMap = new Map([[METHOD_KEY_Transactional, 'Transactional']])

// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-redundant-type-constituents
export type MethodType = (...input: any[]) => (any | Promise<any>)
export type CacheOptions<M extends MethodType | undefined = undefined> =
(Partial<CacheableArgs<M>> | Partial<CacheEvictArgs<M>>) & { op: CacheOperation }
export type CacheOperation = 'Cacheable' | 'CacheEvict' | 'CachePut'

export interface TransactionalArgs<M extends MethodType | undefined = undefined> {
/**
* @default {@link PropagationType.REQUIRED}
*/
propagationType: PropagationType | undefined
/**
* @default {@link TransactionalOptions}
*/
propagationOptions: Partial<TransactionalOptions> | undefined
/**
* @default undefined (no cache)
*/
cacheOptions: CacheOptions<M> | false | undefined
}

import { Msg } from '##/lib/types.js'

export type Method = (...args: unknown[]) => Promise<unknown>
export interface TransactionalDecoratorExecutorOptions extends RegisterTrxPropagateOptions {
/** 装饰器所在类实例 */
instance: new (...args: unknown[]) => unknown
method: Method
methodArgs: unknown[]
// propagationConfig: KmorePropagationConfig
webContext: WebContext
cacheOptions: TransactionalArgs['cacheOptions']
}
import { DecoratorExecutorOptions, GenDecoratorExecutorOptionsExt, TransactionalArgs } from './transactional.types.js'

export type TrxDecoratorMetaData = DecoratorMetaData<TransactionalArgs>

export interface TrxDecoratorExecutorOptions extends DecoratorExecutorParamBase<TransactionalArgs> {
config: KmorePropagationConfig
// trxStatusService: TrxStatusServiceBase
}
export async function genDecoratorExecutorOptionsAsync<T extends object>(
optionsBase: DecoratorExecutorParamBase<T>,
optionsExt: GenDecoratorExecutorOptionsExt,
): Promise<DecoratorExecutorOptions> {

const { mergedDecoratorParam, webContext } = optionsBase

export function genDecoratorExecutorOptions(options: DecoratorExecutorParamBase<TransactionalArgs>): TrxDecoratorExecutorOptions {

const {
decoratorKey,
instance,
method,
methodName,
methodArgs,
mergedDecoratorParam,
webApp,
} = options
assert(webContext, 'webContext is undefined')
assert(webContext.requestContext, 'webContext.requestContext is undefined')

assert(webApp, 'webApp is undefined')
assert(typeof method === 'function', 'options.method is not function')
assert(optionsExt.propagationConfig, Msg.propagationConfigIsUndefined)

const initArgs = {
propagationType: PropagationType.REQUIRED,
propagationOptions: {
...initTransactionalOptions,
},
cacheOptions: false,
}

const trxStatusSvc = await webContext.requestContext.getAsync(TrxStatusService)
assert(trxStatusSvc, 'trxStatusSvc is undefined')

const args = deepmerge.all([
initArgs,
mergedDecoratorParam ?? {},
]) as DecoratorMetaDataPayload<TransactionalArgs>

const config = webApp.getConfig(ConfigKey.propagationConfig) as KmorePropagationConfig
assert(config, 'propagationConfig is undefined')

const ret: TrxDecoratorExecutorOptions = {
...options,
config,
decoratorKey,
const ret: DecoratorExecutorOptions = {
...optionsBase,
...optionsExt,
mergedDecoratorParam: args,
instance,
method,
methodArgs,
methodName,
trxStatusSvc,
}
return ret
}


export async function transactionalDecoratorExecutor(options: TrxDecoratorExecutorOptions): Promise<unknown> {

export async function decoratorExecutor(options: DecoratorExecutorOptions): Promise<unknown> {
const {
instanceName,
mergedDecoratorParam,
methodName,
webContext,
trxStatusSvc,
} = options
// const webContext = options.instance[REQUEST_OBJ_CTX_KEY]
assert(webContext, 'webContext is undefined')
assert(webContext.requestContext, 'webContext.requestContext is undefined')

const trxStatusSvc = await webContext.requestContext.getAsync(TrxStatusService)
assert(trxStatusSvc, 'trxStatusSvc is undefined')


assert(mergedDecoratorParam, 'mergedDecoratorParam is undefined')
assert(mergedDecoratorParam.propagationOptions, 'propagationOptions is undefined')
assert(mergedDecoratorParam?.propagationOptions, 'mergedDecoratorParam.propagationOptions is undefined')

const type = mergedDecoratorParam.propagationType
assert(type, 'propagationType is undefined')
Expand Down Expand Up @@ -180,7 +109,7 @@ export async function transactionalDecoratorExecutor(options: TrxDecoratorExecut
if (! tkey || tkey !== callerKey) {
return resp
}
// ! delay for commit, prevent from method returning Promise or calling Knex builder without `await`
// Delay for commit, prevent from method returning Promise or calling Knex builder without `await`!
await sleep(0)
// only top caller can commit
await trxStatusSvc.trxCommitIfEntryTop(tkey)
Expand All @@ -193,8 +122,6 @@ export async function transactionalDecoratorExecutor(options: TrxDecoratorExecut
trxStatusSvc,
})
}


}

interface ProcessExOptions {
Expand All @@ -213,4 +140,3 @@ async function processEx(options: ProcessExOptions): Promise<never> {
await trxStatusSvc.trxRollbackEntry(callerKey)
throw error
}

Loading

0 comments on commit 5f26166

Please sign in to comment.