node.js - Instanțe singleton multiple în mai multe fișiere în TypeScript și NextJs


Recent, am lucrat la un proiect personal care implică crearea unor endpoint-uri API folosind NextJs și TypeScript care apelează API-ul Discord folosind discord.js. Vă rog să nu vă speriați la menționarea API-ului Discord dacă nu l-ați folosit niciodată, nu cred că acea bibliotecă este problema, motiv pentru care nu este inclusă în titlul thread-ului.

Problemă :

Am implementat un singleton pentru clientul API discord.js, deoarece clientul poate dura aproximativ una sau două secunde pentru a se conecta și a se inițializa, timp pe care nu vreau să-l adaug la fiecare răspuns. Acest lucru funcționează foarte bine pe un singur fișier/endpoint, unde odată ce acel fișier are instanța, o păstrează. Totuși, de îndată ce încarc alt fișier/endpoint, se creează o altă instanță a singleton-ului, însă după crearea sa funcționează din nou bine în cadrul acelui fișier.

Problema mea este că nu vreau o instanță pentru fiecare fișier, ci vreau o singură instanță pentru întreaga aplicație.

DiscordClient.ts:

import { Client } from 'discord.js';

class DiscordClient {
    private static discordClient: DiscordClient;
    public APIClient: Client;

    private constructor() {
        this.APIClient = new Client();
        this.APIClient.login($TOKEN);
    }

    public static get Instance() {
        if (!this.discordClient) {
            this.discordClient = new DiscordClient();
        }
        return this.discordClient;
    }
}

export const DiscordClientInstance = DiscordClient.Instance;

NOTĂ: tokenul este doar un marcator pentru tokenul unic al aplicației mele de bot înregistrată la Discord.

/pages/api/test1.ts

import { DiscordClientInstance } from "../../DiscordClient";


export default (req, res) => {
    let guild = DiscordClientInstance.APIClient.guilds.fetch($GUILD_1_ID)
        .then(guild => {
            console.log(guild.name);
            res.statusCode = 200;
            res.json({ name: guild.name });
        })
        .catch(console.error);
}

/pages/api/test2.ts

import { DiscordClientInstance } from "../../DiscordClient";


export default (req, res) => {
    let guild = DiscordClientInstance.APIClient.guilds.fetch($GUILD_2_ID)
        .then(guild => {
            console.log(guild.name);
            res.statusCode = 200;
            res.json({ name: guild.name });
        })
        .catch(console.error);
}

NOTĂ: $GUILD_#_ID este doar un substitut pentru locul unde ar trebui să meargă ID-ul serverului Discord pe care îl preiau.

Așa cum se poate observa mai sus, test1.ts și test2.ts sunt aproape identice și moștenesc același const.

Dacă cineva are vreo idee despre motivul pentru care se întâmplă acest lucru, aș fi foarte recunoscător. Unele persoane de pe alte site-uri, din căutările mele târzii pe Google, au sugerat că aceasta ar putea fi o problemă legată de Node, însă sincer, nu am nici o idee.

Mulțumesc, Matt :)

Răspuns #1

Folosesc acest model chiar fără probleme - Ai încercat asta în modul de producție? Când ești în modul de dezvoltare, Next.js va compila fiecare pagină la cerere, ceea ce am observat că strică acest model. Practic, dacă vezi „compilare...”, atunci ți-ai pierdut persistența. În modul de producție acest lucru nu se întâmplă și ar trebui să vezi că instanța ta unică este păstrată.