-
-
Notifications
You must be signed in to change notification settings - Fork 496
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
perf: use Domain API instead of async_hooks
After observing huge performance impact when using async_hooks when concurrent requests are involved, Domain API seems like much better fit for this task. Even though they are deprecated, they will most likely stay till another (stable) solution will be available. So far async_hooks caused memory leaks even without ORM being involved. Simple express server with async_hooks tracing enabled created dozens of references in CONTEXT map without properly destroying them (the destroy hook was simply not called for those resource).
- Loading branch information
Martin Adamek
committed
May 27, 2019
1 parent
bcc005e
commit a77bdfd
Showing
2 changed files
with
19 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,33 @@ | ||
import { createHook, executionAsyncId } from 'async_hooks'; | ||
import * as domain from 'domain'; | ||
import { v4 as uuid } from 'uuid'; | ||
import { EntityManager } from '../EntityManager'; | ||
|
||
declare module 'domain' { | ||
export type ORMDomain = Domain & { __mikro_orm_context?: RequestContext }; | ||
const active: ORMDomain; | ||
function create(): ORMDomain; | ||
} | ||
|
||
export class RequestContext { | ||
|
||
static readonly CONTEXT: Record<number, RequestContext> = {}; | ||
readonly id = uuid(); | ||
|
||
constructor(readonly em: EntityManager) { } | ||
|
||
static create(em: EntityManager, next: Function) { | ||
RequestContext.CONTEXT[executionAsyncId()] = new RequestContext(em.fork()); | ||
|
||
const init = (asyncId: number, type: string, triggerId: number) => { | ||
if (RequestContext.CONTEXT[triggerId]) { | ||
RequestContext.CONTEXT[asyncId] = RequestContext.CONTEXT[triggerId]; | ||
} | ||
}; | ||
const destroy = (asyncId: number) => { | ||
delete RequestContext.CONTEXT[asyncId]; | ||
}; | ||
|
||
createHook({ init, destroy }).enable(); | ||
next(); | ||
static create(em: EntityManager, next: (...args: any[]) => void) { | ||
const context = new RequestContext(em.fork()); | ||
const d = domain.create(); | ||
d.__mikro_orm_context = context; | ||
d.run(next); | ||
} | ||
|
||
static currentRequestContext(): RequestContext | null { | ||
return RequestContext.CONTEXT[executionAsyncId()] || null; | ||
static currentRequestContext(): RequestContext | undefined { | ||
return domain.active ? domain.active.__mikro_orm_context : undefined; | ||
} | ||
|
||
static getEntityManager(): EntityManager | null { | ||
static getEntityManager(): EntityManager | undefined { | ||
const context = RequestContext.currentRequestContext(); | ||
return context ? context.em : null; | ||
return context ? context.em : undefined; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters