API Bahagian Belakang Perusahaan NestJS · Pelajaran

Pemutus Litar untuk Kegagalan Perkhidmatan Hiliran

Lindungi perkhidmatan daripada kegagalan berantai menggunakan integrasi pemutus litar gaya opossum.

Pelajaran 2 daripada 413 langkah

Pemutus Litar untuk Kegagalan Perkhidmatan Hiliran ialah pelajaran API Bahagian Belakang Perusahaan NestJS percuma di CoddyKit. Ini ialah pelajaran 2 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran API Bahagian Belakang Perusahaan NestJS, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus API Bahagian Belakang Perusahaan NestJS merangkumi sejumlah 4 pelajaran.

Sebab Kegagalan Berantai Berlaku

Dalam bahagian belakang NestJS perusahaan, perkhidmatan anda jarang beroperasi sendirian. Ia memanggil get laluan pembayaran, penyedia pengesahan, kelompok carian dan perkhidmatan mikro lain. Apabila satu kebergantungan hiliran menjadi perlahan, setiap permintaan yang menunggunya memegang satu sambungan, satu utas dan sebahagian daripada gelung peristiwa.

  • Kebergantungan yang perlahan menghabiskan kumpulan sambungan HTTP anda.
  • Permintaan yang belum selesai bertimbun; kependaman meningkat di mana-mana.
  • Perkhidmatan anda menjadi tidak sihat dan pemanggilnya sendiri mula gagal.

Kesan seperti domino ini ialah kegagalan berantai. Pemutus litar ialah corak yang menghentikan domino daripada terus tumbang.

Mesin Keadaan Pemutus Litar

Pemutus litar membalut satu panggilan berisiko dan menjejaki kesihatannya melalui tiga keadaan:

  • CLOSED — panggilan mengalir seperti biasa. Kegagalan dikira.
  • OPEN — terlalu banyak kegagalan berlaku; panggilan ditolak serta-merta tanpa menyentuh kebergantungan. Ini memberi masa kepada sistem hiliran untuk pulih.
  • SEPARUH_TERBUKA — selepas tempoh penyejukan, beberapa panggilan percubaan dibenarkan. Jika berjaya, pemutus litar ditutup; jika gagal, ia dibuka semula.

Pemahaman utama: apabila pemutus litar berada dalam keadaan OPEN, anda gagal dengan pantas dan bukannya menunggu masa tamat bagi setiap permintaan.

Pemutus Litar Minimum dari Awal

Sebelum menggunakan pustaka, adalah berguna untuk memahami mekanismenya. Berikut ialah pemutus litar kecil yang tersendiri dalam TypeScript, yang bertukar antara CLOSED dan OPEN berdasarkan kegagalan berturut-turut serta masa tamat penetapan semula.

Ini berjalan secara kendiri supaya anda dapat melihat peralihan keadaan.

type State = 'CLOSED' | 'OPEN' | 'HALF_OPEN';

class MiniBreaker {
  private state: State = 'CLOSED';
  private failures = 0;
  private openedAt = 0;
  constructor(private threshold = 3, private resetMs = 1000) {}

  async call<T>(fn: () => Promise<T>): Promise<T> {
    if (this.state === 'OPEN') {
      if (Date.now() - this.openedAt >= this.resetMs) this.state = 'HALF_OPEN';
      else throw new Error('Circuit OPEN: failing fast');
    }
    try {
      const result = await fn();
      this.failures = 0;
      this.state = 'CLOSED';
      return result;
    } catch (e) {
      this.failures++;
      if (this.failures >= this.threshold) {
        this.state = 'OPEN';
        this.openedAt = Date.now();
      }
      throw e;
    }
  }
  get current() { return this.state; }
}

async function main() {
  const breaker = new MiniBreaker(2, 500);
  const flaky = () => Promise.reject(new Error('downstream down'));
  for (let i = 0; i < 4; i++) {
    try { await breaker.call(flaky); }
    catch (e) { console.log(`call ${i}: ${(e as Error).message} [state=${breaker.current}]`); }
  }
}
main();

Memperkenalkan opossum

Pemutus litar buatan sendiri sering terlepas bahagian yang sukar: statistik tetingkap bergerak, ambang berasaskan peratusan, had percubaan separuh terbuka dan metrik. opossum ialah pemutus litar Node.js yang menjadi pilihan umum dan berintegrasi dengan baik ke dalam penyedia NestJS.

  • timeout — tempoh sebelum panggilan dianggap gagal.
  • errorThresholdPercentage — peratus kegagalan dalam tetingkap yang mencetuskan pemutus litar.
  • resetTimeout — tempoh keadaan OPEN sebelum percubaan HALF_OPEN.
  • rollingCountTimeout — saiz tetingkap statistik.

Pasangnya dengan npm i opossum dan npm i -D @types/opossum.

import CircuitBreaker from 'opossum';

const options: CircuitBreaker.Options = {
  timeout: 3000,                 // a call slower than 3s counts as a failure
  errorThresholdPercentage: 50,  // trip when >=50% of calls fail
  resetTimeout: 10000,           // stay OPEN for 10s, then try HALF_OPEN
  rollingCountTimeout: 10000,    // 10s statistical window
  rollingCountBuckets: 10,       // split the window into 10 buckets
};

// The action is the function we want to protect
async function fetchUser(id: string): Promise<{ id: string }> {
  // ... real HTTP call to a downstream user service ...
  return { id };
}

export const userBreaker = new CircuitBreaker(fetchUser, options);

Membalut Panggilan Hiliran dalam Penyedia NestJS

Dalam NestJS, pemutus litar hendaklah berada dalam penyedia yang memiliki satu kebergantungan logik. Bina CircuitBreaker sekali sahaja dalam pembina (atau kilang) supaya statistik tetingkap bergerak kekal merentas permintaan — jangan sekali-kali mencipta pemutus litar baharu bagi setiap permintaan, kerana pemutus itu tidak akan dapat mempelajari kesihatan kebergantungan.

Dedahkan satu kaedah yang menyerahkan panggilan kepada breaker.fire(...).

import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';
import CircuitBreaker from 'opossum';

interface PricingDto { sku: string; cents: number; }

@Injectable()
export class PricingClient {
  private readonly breaker: CircuitBreaker<[string], PricingDto>;

  constructor(private readonly http: HttpService) {
    this.breaker = new CircuitBreaker(
      (sku: string) => this.requestPrice(sku),
      { timeout: 2000, errorThresholdPercentage: 50, resetTimeout: 15000 },
    );
  }

  private async requestPrice(sku: string): Promise<PricingDto> {
    const res = await firstValueFrom(
      this.http.get<PricingDto>(`https://pricing.internal/skus/${sku}`),
    );
    return res.data;
  }

  getPrice(sku: string): Promise<PricingDto> {
    return this.breaker.fire(sku);
  }
}

Sandaran: Merosot dengan Lancar

Gagal dengan pantas memang baik, tetapi memulangkan ralat keras kepada pengguna selalunya lebih buruk daripada memulangkan sesuatu yang munasabah. fallback() opossum berjalan apabila tindakan ditolak atau pemutus litar berada dalam keadaan OPEN.

  • Hidangkan nilai yang dicache atau nilai terakhir yang diketahui baik.
  • Mulangkan nilai lalai yang selamat (contohnya, senarai pengesyoran yang kosong).
  • Masukkan kerja ke dalam baris gilir untuk diproses kemudian dan bukannya membuangnya.

Sandaran menerima argumen yang sama serta ralat yang mencetuskannya, jadi anda boleh membuat percabangan berdasarkan ralat tersebut.

import CircuitBreaker from 'opossum';

type Recommendation = { id: string };

function buildRecommendationBreaker(
  action: (userId: string) => Promise<Recommendation[]>,
) {
  const breaker = new CircuitBreaker(action, {
    timeout: 1500,
    errorThresholdPercentage: 40,
    resetTimeout: 20000,
  });

  // When OPEN or the action fails, return a safe empty list
  breaker.fallback((_userId: string, err?: Error) => {
    if (err) console.warn('recommendations degraded:', err.message);
    return [] as Recommendation[];
  });

  return breaker;
}

Mendengar Peristiwa Pemutus Litar

Pemutus litar yang bertukar keadaan secara senyap merupakan titik buta operasi. opossum mengeluarkan peristiwa bagi setiap peralihan yang bermakna. Sambungkan peristiwa ini kepada pengelogan dan metrik anda supaya jurutera bertugas dapat melihat gambaran semasa dalam masa nyata.

  • open / halfOpen / close — peralihan keadaan.
  • reject — panggilan ditolak kerana pemutus litar berada dalam keadaan OPEN.
  • timeout — panggilan melebihi masa tamat yang dikonfigurasikan.
  • fallback — sandaran dipanggil.
  • success / failure — hasil setiap panggilan yang dicetuskan.
import { Logger } from '@nestjs/common';
import CircuitBreaker from 'opossum';

export function attachBreakerTelemetry(
  breaker: CircuitBreaker,
  name: string,
  logger = new Logger('CircuitBreaker'),
) {
  breaker.on('open', () => logger.error(`[${name}] OPEN - failing fast`));
  breaker.on('halfOpen', () => logger.warn(`[${name}] HALF_OPEN - probing`));
  breaker.on('close', () => logger.log(`[${name}] CLOSED - recovered`));
  breaker.on('reject', () => logger.warn(`[${name}] call rejected (OPEN)`));
  breaker.on('timeout', () => logger.warn(`[${name}] call timed out`));
  breaker.on('fallback', () => logger.warn(`[${name}] fallback served`));
}

Masa Tamat Sebahagian daripada Pemutus Litar

Kesilapan biasa ialah menetapkan timeout pemutus litar lebih lama daripada masa tamat klien HTTP asas. Jika masa tamat axios anda ialah 30s tetapi masa tamat pemutus litar ialah 3s, opossum berhenti menunggu selepas 3s — bagus — tetapi soket mungkin masih terbuka dan dipegang pada sistem hiliran.

Selaraskannya: tetapkan masa tamat pemutus litar sedikit lebih rendah daripada masa tamat pengangkutan, dan pastikan pengangkutan benar-benar membatalkan panggilan. Tujuan utamanya ialah mengehadkan tempoh setiap panggilan boleh mengikat sesuatu sumber.

import { Module } from '@nestjs/common';
import { HttpModule } from '@nestjs/axios';

@Module({
  imports: [
    HttpModule.register({
      timeout: 2500,        // axios aborts the socket at 2.5s
      maxRedirects: 0,
    }),
  ],
})
export class DownstreamModule {}

// Breaker timeout (e.g. 2000ms) should sit just BELOW the axios timeout
// so opossum records the failure while the socket is still being released.

Satu Pemutus bagi Setiap Kebergantungan, Bukan bagi Setiap Aplikasi

Pemisahan beban bermaksud mengasingkan kegagalan supaya kebergantungan yang bermasalah tidak menenggelamkan kebergantungan yang sihat. Berikan setiap sistem hiliran tika pemutus litarnya sendiri dengan ambang yang dilaraskan mengikut SLA-nya.

  • Perkhidmatan analitik yang tidak stabil boleh tercetus tanpa menjejaskan pembayaran.
  • Panggilan pengesahan yang sensitif terhadap kependaman mendapat masa tamat yang ketat; panggilan laporan kelompok mendapat masa tamat yang longgar.
  • Metrik mengikut kebergantungan menjadikan papan pemuka mudah dibaca.

Jangan kongsi satu pemutus litar global merentas panggilan yang tidak berkaitan — statistiknya akan mencemari satu sama lain.

import { Injectable } from '@nestjs/common';
import CircuitBreaker from 'opossum';

@Injectable()
export class BreakerRegistry {
  private readonly breakers = new Map<string, CircuitBreaker>();

  get<TArgs extends unknown[], TRet>(
    name: string,
    action: (...args: TArgs) => Promise<TRet>,
    options: CircuitBreaker.Options,
  ): CircuitBreaker<TArgs, TRet> {
    const existing = this.breakers.get(name);
    if (existing) return existing as CircuitBreaker<TArgs, TRet>;
    const breaker = new CircuitBreaker(action, options);
    this.breakers.set(name, breaker);
    return breaker;
  }
}

Mendedahkan Kesihatan Pemutus kepada Probe

Dari sudut operasi, anda mahu keadaan pemutus litar kelihatan pada titik akhir kesihatan dan dikumpulkan oleh Prometheus. opossum mendedahkan breaker.stats (bilangan kejayaan, kegagalan, masa tamat dan penolakan) serta boolean breaker.opened / breaker.halfOpen.

Penunjuk kesihatan Terminus tersuai boleh melaporkan pemutus litar OPEN sebagai status terdegradasi — tidak semestinya tidak berfungsi — supaya penyelaras tidak membunuh pod yang sebenarnya sedang mengurangkan beban dengan betul.

import { Injectable } from '@nestjs/common';
import { HealthIndicator, HealthIndicatorResult } from '@nestjs/terminus';
import CircuitBreaker from 'opossum';

@Injectable()
export class BreakerHealthIndicator extends HealthIndicator {
  check(name: string, breaker: CircuitBreaker): HealthIndicatorResult {
    const isUp = !breaker.opened;
    return this.getStatus(name, isUp, {
      state: breaker.opened ? 'open' : breaker.halfOpen ? 'half_open' : 'closed',
      failures: breaker.stats.failures,
      timeouts: breaker.stats.timeouts,
      rejects: breaker.stats.rejects,
    });
  }
}

Melaraskan Ambang dengan Wajar

Ambang yang buruk lebih teruk daripada tiada pemutus litar. Laraskannya berdasarkan trafik sebenar:

  • errorThresholdPercentage yang terlalu rendah (contohnya 10%) akan tercetus akibat turun naik biasa; yang terlalu tinggi (contohnya 90%) menggagalkan tujuannya. 40–60% ialah julat permulaan yang biasa.
  • resetTimeout yang terlalu singkat akan terus menghentam perkhidmatan yang sedang pulih; yang terlalu lama melambatkan pemulihan. Mulakan sekitar 10–30s.
  • Ambil kira trafik rendah: dengan hanya 2 panggilan dalam tetingkap, satu kegagalan bersamaan 50%. volumeThreshold opossum memerlukan bilangan panggilan minimum sebelum peratusan boleh mencetuskan pemutus.
import CircuitBreaker from 'opossum';

const options: CircuitBreaker.Options = {
  timeout: 2000,
  errorThresholdPercentage: 50,
  resetTimeout: 15000,
  rollingCountTimeout: 10000,
  rollingCountBuckets: 10,
  volumeThreshold: 10, // need >=10 calls in the window before % can trip
  // errorFilter lets you NOT count expected errors (e.g. 404) as failures:
  errorFilter: (err: { statusCode?: number }) => err?.statusCode === 404,
};

export { options };

Semakan Pantas: Memilih Tingkah Laku yang Betul

Uji pemahaman anda tentang cara pemutus litar bertindak di bawah beban.

Imbas Kembali

Sekarang anda tahu cara menghalang kegagalan hiliran daripada menjatuhkan perkhidmatan NestJS anda:

  • Corak: pemutus bergerak antara CLOSED, OPEN dan HALF_OPEN; OPEN bermaksud gagal dengan pantas dan bukannya menunggu masa tamat.
  • opossum: konfigurasikan timeout, errorThresholdPercentage, resetTimeout dan volumeThreshold, kemudian balut panggilan dengan new CircuitBreaker(action, options) dan panggil breaker.fire().
  • Bina sekali: cipta pemutus dalam penyedia/pendaftaran supaya statistik tetingkap bergerak kekal — satu pemutus bagi setiap kebergantungan untuk pemisahan beban.
  • Kurangkan keupayaan: daftarkan fallback() untuk respons yang dicache atau lalai yang selamat.
  • Pantau: sambungkan peristiwa open/close/reject/timeout kepada log dan metrik, serta paparkan keadaan pada probe kesihatan.

Apabila digabungkan dengan cubaan semula (dengan penangguhan) dan masa tamat, pemutus litar menjadi asas utama sistem teragih yang berdaya tahan dan mesra SLO.

Percuma untuk bermula

Pelajari TypeScript dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
20
Pelajaran
76

Soalan Lazim

Adakah pelajaran “Pemutus Litar untuk Kegagalan Perkhidmatan Hiliran” percuma?

Ya — teks penuh “Pemutus Litar untuk Kegagalan Perkhidmatan Hiliran” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus API Bahagian Belakang Perusahaan NestJS, tingkat taraf kepada CoddyKit PRO. Kursus API Bahagian Belakang Perusahaan NestJS merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Pemutus Litar untuk Kegagalan Perkhidmatan Hiliran”?

Lindungi perkhidmatan daripada kegagalan berantai menggunakan integrasi pemutus litar gaya opossum. Anda berlatih API Bahagian Belakang Perusahaan NestJS menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan API Bahagian Belakang Perusahaan NestJS?

Tiada pengalaman terdahulu diperlukan. Pembelajaran API Bahagian Belakang Perusahaan NestJS di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 2 daripada 4.

Berapa lamakah pelajaran “Pemutus Litar untuk Kegagalan Perkhidmatan Hiliran” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran API Bahagian Belakang Perusahaan NestJS ini?

Ya. Setiap pelajaran API Bahagian Belakang Perusahaan NestJS menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Had Masa, Percubaan Semula dan Sekatan dengan Interceptor
  2. Pemutus Litar untuk Kegagalan Perkhidmatan Hiliran
  3. Jejak Teragih dengan OpenTelemetry
  4. Mentakrifkan SLO dan Belanjawan Ralat
← Kembali ke API Bahagian Belakang Perusahaan NestJS