Thursday, 21 January 2021

Memory leak in TypeScript class with interval and mongoose fetching

I made this class in TypeScript.. It has a websocket which will emit data which is pre-fetched with mongoose based on some parameters.

PLEASE NOTE: This is demo code, not the real one. I replicated it to be as easily understandable as possible

import { Server as SocketServer } from 'socket.io';
import { Animal, AnimalModel } from './animal.model.ts'; 
// ^^^^^^^ this is just a basic properties interface and a mongoose schema

export class Stream {
    private io: SocketServer;
    private breed: string;
    private animals: Array<Animal>;
  
    constructor(
        io: SocketServer,
        breed: string
    ) {
      this.io = io;
      this.breed = breed;
      
      this.fetch(); // initial fetch
      setInterval(() => this.emit(), 1000); // emit every second
      setInterval(() => this.fetch(), 1000); // fetch it every second for updates
      // ^^^ once I comment this line out, it doesn't seem to leak memory anymore
    }

    /**
    * Fetch the animals list based on the set breed
    */ 
    private async fetch(): Promise<void> {
       this.animals = await AnimalModel.find({breed: this.breed}).limit(20).exec(); // one fetch is about 100kb
    }

    /**
    * Emit the animals list to people who are subscribed to the breed
    */
    private emit(): void {
        this.io.in(this.breed).emit("animals", JSON.stringify(this.animals))
    }  
}

And I generate these animals like this:

import { AnimalModel } from './animal.model.ts'; 

const socket = makeSocket(); // some function to make new socket.io instance

const initialize = async () => {
    // About 25 animals
    const animalsList = await AnimalModel.find().exec();
    animalsList.forEach(animal => {
       new Stream(socket, animal.breed); // generates a new stream for every animal breed with a reference to the socket
    });
};

initialize();

Now the problem is that one fetch of animals (per breed) is about 100kb, multiply that by 25 and that's about 2,5 MB added to the memory heap every second. Whenever I comment the fetch out, it does not increase further. To me it looks like that fetch function is not being released.

I have been trying for hours and I can not get this to work, like using the Chrome NodeJS debug tool, writing different functions - but with no result.. Can anyone help me out with this or come up with code that does not leak?

PS: I have some Heap snapshots in case it's needed



from Memory leak in TypeScript class with interval and mongoose fetching

No comments:

Post a Comment