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å:

  1. 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) {}
  1. 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

Relaterte artikler