javascript - Trenger hjelp med å identifisere minnelekkasje ved bruk av express i node


Problemet

Jeg har en Node-applikasjon som kjører i ECS, og som ser ut til å lekke minne, siden minnet stadig vokser og synker ved hver distribusjon.

Jeg lagde en heapdump og importerte den i Chrome DevTools, og prøvde å få litt forståelse av den.

Heapdump

Det ser ut til å være flere hundre tusen strenger som ser slik ut. Syntaksen ser ut som express res.cookie syntaksen jeg har i mellomvaren min, og selvfølgelig også i innloggingsruten. Den mellomvaren jeg har som sjekker om brukeren har en gyldig cookie, og oppdaterer den hvis den er gyldig. Siden den ville kjøre oftere, tror jeg det gir mening at mellomvaren er synderen, men jeg kan fortsatt ikke skjønne hvorfor den lekker.

Den mulige gjerningspersonen? Middleware.ts

import * as jwt from 'jsonwebtoken';
import issueJWT from 'utils/functions/IssueToken';
import { getRepository, getConnection } from 'typeorm';
import User from 'entity/organization/User';
import { ApiResult } from 'utils/classes/ApiResult';

interface ICookie {
    name: string;
    payload: string;
}

interface ICookieRouterConnections {
    routeName: string;
    cookieName: string;
}

const authenticate = async (req, res, next) => {
    const userRepository = getRepository(User);
    const { authorization, cookie } = req.headers;
    let requestToken: ICookie = { name: '', payload: '' };

    // These are the tokens that can be issued with their corresponding routes
    const portalCookieNames: ICookieRouterConnections[] = [
        {
            routeName: 'admin',
            cookieName: process.env.JWT_ADMIN,
        },
        {
            routeName: 'customer',
            cookieName: process.env.JWT_CUSTOMER,
        },
    ];

    // Find the router the user is trying to access
    const requestedRouterName = req.path
        .split('/')
        .splice(1, 1)
        .shift();

    function throwError(statusObj: { message: string; code: string; statusCode: number }) {
        const apiResult = new ApiResult();
        apiResult.addError({
            message: statusObj.message,
            code: statusObj.code,
            request: req,
        });
        res.status(statusObj.statusCode);
        res.send(apiResult);
    }

    // Gets the value of a cookie by the cookie name
    const getCookie = (cookieName: string): ICookie => {
        const returnObject = {
            name: cookieName,
            payload: cookie
                .split(`${cookieName}=`)
                .pop()
                .split(';')
                .shift(),
        };
        return returnObject;
    };

    const routerCookieName = portalCookieNames.find(obj => obj.routeName === requestedRouterName).cookieName;

    if (!authorization && !cookie) {
        throwError({ message: 'Token not provided', statusCode: 401, code: 'tokenNotProvided' });
        return;
    }

    // If there is authorization header, use that
    if (authorization) {
        requestToken.name = routerCookieName;
        requestToken.payload = authorization.replace('Bearer ', '');
    } else {
        // If not use the JWT from the cookie based on which router the user is trying to access
        requestToken = getCookie(routerCookieName);
    }

    if (requestToken) {
        // Validate the token
        jwt.verify(requestToken.payload, process.env.APP_SECRET, async (err, decoded) => {
            if (err) {
                throwError({ message: err, statusCode: 401, code: 'internalError' });
            } else {
                const user = await userRepository.findOne({ where: { id: decoded.userId } });

                if (!user.isDeactivated) {
                    req.user = user;
                    // Issue a new token if the cookie provided was valid
                    res.cookie(requestToken.name, issueJWT(user), {
                        httpOnly: false,
                        expires: new Date(Date.now() + 24 * 3600000),
                        domain: process.env.COOKIE_DOMAIN,
                    });
                    next();
                }
            }
        });
    } else {
        throwError({ message: 'Invalid token', statusCode: 401, code: 'invalidTokenProvided' });
    }
};

export default authenticate;


Svar #1

Jeg tror Bergi pekte meg i riktig retning.

Dette var en pakke "express-session" som ble lastet inn i ruteren. Det ser ut til at standard minnelager lekker og ikke bør brukes i produksjon.

Fra npmjs-repositoriet

Advarsel Standard server-side sesjonslagring, MemoryStore, er bevisst ikke designet for et produksjonsmiljø. Den vil lekke minne under de fleste forhold, skalerer ikke utover en enkelt prosess, og er ment for feilsøking og utvikling.

Relaterte artikler