javascript - Tjenester med forespørselsomfang
Så vidt jeg forsto, oppretter NestJs alle tjenestene når applikasjonen starter. Kanskje jeg bruker det feil. Finnes det en måte å konfigurere NestJs til å opprette tjenester basert på forespørsel? Som at hver gang en forespørsel gjøres, blir noen tjenester som brukes i den forespørselen gjenskapt?
Svar #1
Med utgivelsen av nest.js 6.0 ble injeksjonsscopes lagt til. Med dette kan du velge ett av de følgende tre scopes for dine providere:
- SINGLETON: Standard oppførsel. Én instans av leverandøren din brukes for hele applikasjonen
- TRANSIENT: En dedikert instans av leverandøren din opprettes for hver leverandør som injiserer den.
- FORESPØRSEL: For hver forespørsel opprettes en ny leverandør.
⚠️ Forsiktighet: Injeksjonsområdet vil boble opp i avhengighetskjeden din. ⚠️
Eksempel: Hvis UsersController (singleton omfang) injiserer UsersService (singleton omfang) som injiserer OtherService (forespørselsomfang), vil både UsersController og UsersService automatisk bli forespørselsomfang.
Bruk
Legg det enten til i @Injectable()-dekoren:
@Injectable({ scope: Scope.REQUEST })
export class UsersService {}
Eller sett det for tilpassede leverandører i moduldefinisjonen din:
{
provide: 'CACHE_MANAGER',
useClass: CacheManager,
scope: Scope.TRANSIENT,
}
Svar #2
Det er mulig med en innebygd avhengighetsinjeksjonsmekanisme med forespørselsomfang https://docs.nestjs.com/fundamentals/injection-scopes men det har alvorlige ulemper ifølge dokumentasjonen:
Omfang bobler opp injeksjonskjeden. En kontroller som er avhengig av en request-skopet leverandør vil selv være request-skopet.
Å bruke leverandører med forespørselsomfang vil påvirke applikasjonens ytelse. Selv om Nest prøver å cache så mye metadata som mulig, må det fortsatt opprette en instans av klassen din ved hver forespørsel. Derfor vil det senke gjennomsnittlig responstid og den samlede benchmark-resultatet ditt. Med mindre en leverandør må være med forespørselsomfang, anbefales det sterkt at du bruker standard singleton-omfanget.
Nylig har jeg laget en request-scope implementering for NestJS som er fri for oppblomstring i injeksjonskjeden og ytelsespåvirkning.
https://github.com/kugacz/nj-request-scope
For å bruke det må du først legge til import av RequestScopeModule i modulklassedekoratoren:
import { RequestScopeModule } from 'nj-request-scope';
@Module({
imports: [RequestScopeModule],
})
Deretter er det to måter å injisere i request-scope på:
- Injiser express request-objektet i klassekonstruktøren med NJRS_REQUEST-token:
import { NJRS_REQUEST } from 'nj-request-scope';
[...]
constructor(@Inject(NJRS_REQUEST) private readonly request: Request) {}
- Endre klasseinjeksjonens omfang til request-scope med @RequestScope() dekoratør:
import { RequestScope } from 'nj-request-scope';
@Injectable()
@RequestScope()
export class RequestScopeService {
Du kan finne eksempeimplementasjoner i dette depotet: https://github.com/kugacz/nj-request-scope-example NestJS hva er beste praksis for å initialisere og sende forespørselkontekst Jeg tror du kan bruke nj-request-scope-pakken jeg skrev. Den er fri for oppblåsing i injeksjonskjeden og ytelsesproblemer:
https://github.com/kugacz/nj-request-scope
Først må du legge til import av RequestScopeModule i klasse-dekoratøren for modulen:
import { RequestScopeModule } from 'nj-request-scope';
@Module({
imports: [RequestScopeModule],
})
og da kan din RequestContext-klasse skrives slik:
import { Injectable } from '@nestjs/common';
import { Request } from 'express';
import { IncomingHttpHeaders } from 'http';
import { RequestScope } from 'nj-request-scope';
import { NJRS_REQUEST } from 'nj-request-scope';
@Injectable()
@RequestScope()
export class RequestContext {
public headers: IncomingHttpHeaders;
....
constructor(@Inject(NJRS_REQUEST) private readonly request: Request) {
this.headers = request.headers;
}
}
I så fall vil en ny forekomst av RequestContext-klassen bli opprettet for hver forespørsel. Så du kan lagre hvilken som helst informasjonsom har forespørselsomfang inni denne klassen. Å injisere denne klassen i hvilken som helst del av applikasjonen din vil ikke forårsake en oppstigende injeksjonskjede.
En annen tilnærming er slik:
import { Injectable } from '@nestjs/common';
import { Request } from 'express';
import { IncomingHttpHeaders } from 'http';
import { NJRS_REQUEST } from 'nj-request-scope';
@Injectable()
export class RequestContext {
constructor(@Inject(NJRS_REQUEST) private readonly request: Request) {
}
public get headers(): IncomingHttpHeaders {
return this.request.headers;
}
}
I så fall er RequestContext-klassen singleton-scope og bare request-feltet er request-scope. Så du kan ikke lagre noen request-scope-informasjon direkte i RequestContext-klassen, men du må lese request-scope-data direkte fra request-objektet via getters. Også vil det å injisere denne klassen i noen del av applikasjonen din ikke føre til en oppadgående injeksjonskjede.
Enkle eksempler på bruk av nj-request-scope-pakken finner du her: https://github.com/kugacz/nj-request-scope-example
