Skip to content

Commit 77a8027

Browse files
feat(core): use static exception filters for request-scope
1 parent ec5dd36 commit 77a8027

4 files changed

Lines changed: 102 additions & 37 deletions

File tree

packages/core/middleware/middleware-module.ts

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { ApplicationConfig } from '../application-config';
1212
import { InvalidMiddlewareException } from '../errors/exceptions/invalid-middleware.exception';
1313
import { RuntimeException } from '../errors/exceptions/runtime.exception';
1414
import { createContextId } from '../helpers/context-id-factory';
15+
import { ExecutionContextHost } from '../helpers/execution-context-host';
1516
import { NestContainer } from '../injector/container';
1617
import { InstanceWrapper } from '../injector/instance-wrapper';
1718
import { Module } from '../injector/module';
@@ -26,6 +27,8 @@ import { RoutesMapper } from './routes-mapper';
2627

2728
export class MiddlewareModule {
2829
private readonly routerProxy = new RouterProxy();
30+
private readonly exceptionFiltersCache = new WeakMap();
31+
2932
private injector: Injector;
3033
private routerExceptionFilter: RouterExceptionFilters;
3134
private routesMapper: RoutesMapper;
@@ -190,18 +193,32 @@ export class MiddlewareModule {
190193
res: TResponse,
191194
next: () => void,
192195
) => {
193-
const contextId = createContextId();
194-
const contextInstance = await this.injector.loadPerContext(
195-
instance,
196-
module,
197-
collection,
198-
contextId,
199-
);
200-
const proxy = await this.createProxy<TRequest, TResponse>(
201-
contextInstance,
202-
contextId,
203-
);
204-
return proxy(req, res, next);
196+
try {
197+
const contextId = createContextId();
198+
const contextInstance = await this.injector.loadPerContext(
199+
instance,
200+
module,
201+
collection,
202+
contextId,
203+
);
204+
const proxy = await this.createProxy<TRequest, TResponse>(
205+
contextInstance,
206+
contextId,
207+
);
208+
return proxy(req, res, next);
209+
} catch (err) {
210+
let exceptionsHandler = this.exceptionFiltersCache.get(instance.use);
211+
if (!exceptionsHandler) {
212+
exceptionsHandler = this.routerExceptionFilter.create(
213+
instance,
214+
instance.use,
215+
undefined,
216+
);
217+
this.exceptionFiltersCache.set(instance.use, exceptionsHandler);
218+
}
219+
const host = new ExecutionContextHost([req, res, next]);
220+
exceptionsHandler.next(err, host);
221+
}
205222
},
206223
);
207224
}

packages/core/router/router-explorer.ts

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { UnknownRequestMappingException } from '../errors/exceptions/unknown-req
1414
import { GuardsConsumer } from '../guards/guards-consumer';
1515
import { GuardsContextCreator } from '../guards/guards-context-creator';
1616
import { createContextId } from '../helpers/context-id-factory';
17+
import { ExecutionContextHost } from '../helpers/execution-context-host';
1718
import { ROUTE_MAPPED_MESSAGE } from '../helpers/messages';
1819
import { RouterMethodFactory } from '../helpers/router-method-factory';
1920
import { STATIC_CONTEXT } from '../injector/constants';
@@ -42,6 +43,7 @@ export class RouterExplorer {
4243
private readonly executionContextCreator: RouterExecutionContext;
4344
private readonly routerMethodFactory = new RouterMethodFactory();
4445
private readonly logger = new Logger(RouterExplorer.name, true);
46+
private readonly exceptionFiltersCache = new WeakMap();
4547

4648
constructor(
4749
private readonly metadataScanner: MetadataScanner,
@@ -189,24 +191,43 @@ export class RouterExplorer {
189191
res: TResponse,
190192
next: () => void,
191193
) => {
192-
const contextId = createContextId();
193-
this.registerRequestProvider(req, contextId);
194+
try {
195+
const contextId = createContextId();
196+
this.registerRequestProvider(req, contextId);
194197

195-
const contextInstance = await this.injector.loadPerContext(
196-
instance,
197-
module,
198-
collection,
199-
contextId,
200-
);
201-
this.createCallbackProxy(
202-
contextInstance,
203-
contextInstance[methodName],
204-
methodName,
205-
moduleKey,
206-
requestMethod,
207-
contextId,
208-
instanceWrapper.id,
209-
)(req, res, next);
198+
const contextInstance = await this.injector.loadPerContext(
199+
instance,
200+
module,
201+
collection,
202+
contextId,
203+
);
204+
this.createCallbackProxy(
205+
contextInstance,
206+
contextInstance[methodName],
207+
methodName,
208+
moduleKey,
209+
requestMethod,
210+
contextId,
211+
instanceWrapper.id,
212+
)(req, res, next);
213+
} catch (err) {
214+
let exceptionFilter = this.exceptionFiltersCache.get(
215+
instance[methodName],
216+
);
217+
if (!exceptionFilter) {
218+
exceptionFilter = this.exceptionsFilter.create(
219+
instance,
220+
instance[methodName],
221+
moduleKey,
222+
);
223+
this.exceptionFiltersCache.set(
224+
instance[methodName],
225+
exceptionFilter,
226+
);
227+
}
228+
const host = new ExecutionContextHost([req, res, next]);
229+
exceptionFilter.next(err, host);
230+
}
210231
};
211232

212233
paths.forEach(path => {

packages/microservices/listeners-controller.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Controller } from '@nestjs/common/interfaces/controllers/controller.interface';
22
import { createContextId } from '@nestjs/core/helpers/context-id-factory';
3+
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
34
import { NestContainer } from '@nestjs/core/injector/container';
45
import { Injector } from '@nestjs/core/injector/injector';
56
import {
@@ -10,6 +11,7 @@ import { MetadataScanner } from '@nestjs/core/metadata-scanner';
1011
import { REQUEST } from '@nestjs/core/router/request/request-constants';
1112
import { IClientProxyFactory } from './client/client-proxy-factory';
1213
import { ClientsContainer } from './container';
14+
import { ExceptionFiltersContext } from './context/exception-filters-context';
1315
import { RpcContextCreator } from './context/rpc-context-creator';
1416
import { CustomTransportStrategy, RequestContext } from './interfaces';
1517
import { ListenerMetadataExplorer } from './listener-metadata-explorer';
@@ -19,13 +21,15 @@ export class ListenersController {
1921
private readonly metadataExplorer = new ListenerMetadataExplorer(
2022
new MetadataScanner(),
2123
);
24+
private readonly exceptionFiltersCache = new WeakMap();
2225

2326
constructor(
2427
private readonly clientsContainer: ClientsContainer,
2528
private readonly contextCreator: RpcContextCreator,
2629
private readonly container: NestContainer,
2730
private readonly injector: Injector,
2831
private readonly clientFactory: IClientProxyFactory,
32+
private readonly exceptionFiltersContext: ExceptionFiltersContext,
2933
) {}
3034

3135
public bindPatternHandlers(
@@ -50,9 +54,9 @@ export class ListenersController {
5054
);
5155
return server.addHandler(pattern, proxy, isEventHandler);
5256
}
53-
server.addHandler(
54-
pattern,
55-
async (data: unknown) => {
57+
const asyncHandler = async (...args: unknown[]) => {
58+
try {
59+
const data = args[0];
5660
const contextId = createContextId();
5761
this.registerRequestProvider({ pattern, data }, contextId);
5862

@@ -68,9 +72,26 @@ export class ListenersController {
6872
moduleKey,
6973
);
7074
return proxy(data);
71-
},
72-
isEventHandler,
73-
);
75+
} catch (err) {
76+
let exceptionFilter = this.exceptionFiltersCache.get(
77+
instance[methodKey],
78+
);
79+
if (!exceptionFilter) {
80+
exceptionFilter = this.exceptionFiltersContext.create(
81+
instance,
82+
instance[methodKey],
83+
moduleKey,
84+
);
85+
this.exceptionFiltersCache.set(
86+
instance[methodKey],
87+
exceptionFilter,
88+
);
89+
}
90+
const host = new ExecutionContextHost(args);
91+
exceptionFilter.handle(err, host);
92+
}
93+
};
94+
server.addHandler(pattern, asyncHandler, isEventHandler);
7495
},
7596
);
7697
}

packages/microservices/microservices-module.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,14 @@ export class MicroservicesModule {
2424
private listenersController: ListenersController;
2525

2626
public register(container: NestContainer, config: ApplicationConfig) {
27+
const rpcProxy = new RpcProxy();
28+
const exceptionFiltersContext = new ExceptionFiltersContext(
29+
container,
30+
config,
31+
);
2732
const contextCreator = new RpcContextCreator(
28-
new RpcProxy(),
29-
new ExceptionFiltersContext(container, config),
33+
rpcProxy,
34+
exceptionFiltersContext,
3035
new PipesContextCreator(container, config),
3136
new PipesConsumer(),
3237
new GuardsContextCreator(container, config),
@@ -40,6 +45,7 @@ export class MicroservicesModule {
4045
container,
4146
new Injector(),
4247
ClientProxyFactory,
48+
exceptionFiltersContext,
4349
);
4450
}
4551

0 commit comments

Comments
 (0)