Streaming a large zip file from NodeJS, Express

I want to downaload a large zip file of 3GB consisting 2000 or more images with their thumbnails to mobile application depending on user’s request from my NodeJS Express server using a route.

Zip file is created using archiver inside a worker. it works fine up to this point.

On my local machine it is too-good but on production, sometimes it works really fast when streaming and sometimes it takes too-long that it reaches timeout after 5 to 10% of download only. Even at that time there no such load on server.

Following is something like my implementation. I can’t figure out the actual problem.
Is it beacuse when my internet is slow, the server sends data very slowly to match my download speed or it’s something else??

const fs = require('fs');
const fsPromises = require('fs/promises');
const crypto = require('crypto');
const path = require('path');
const { logger } = require('config/winston');

const downloadZip = async (req, res) => {
  // Create archive
  const fnm = 'file_' + crypto.randomBytes(8).toString('hex');
  const zipName = fnm + 'zip';
  const zipFilePath = path.join('tmpfolder', zipName);
  // Get archive from worker
  try {
    const images = await getImages();
    zipStatus = await zipWorker(images);
  } catch (err) {
    throw `Error in creating zip.`;
  }
  // Get stats
  let zipSize = 0;
  try {
    const zipStats = await fsPromises.stat(zipFilePath);
    zipSize = zipStats.size || 0;
  } catch (err) {
    throw `Zip stats not found.`;
  }
  // Download
  logger.verbose(`Preparing to download.`);
  res.setHeader('Content-Type', 'application/zip');
  res.setHeader('Content-Disposition', `attachment; filename=images.zip`);
  res.setHeader('Content-Length', zipSize);
  const resFile = fs.createReadStream(zipFilePath);
  resFile.pipe(res);
  resFile.on('error', err => {
    logger.error(`Error in streaming zip.`);
    res.end();
  });
  // Print downloading percent on server
  let bytesSent = 0;
  resFile.on('data', chunk => {
    if (zipSize > 0) {
      bytesSent += chunk?.length;
      const percentage = ((bytesSent / zipSize) * 100).toFixed(2);
      logger.verbose(`Downloading ${percentage}%`); // <== Downloading completed in %
    }
  });
  // If completed
  resFile.on('end', () => {
    logger.verbose(`Images downloaded.`);
  });
  res.on('close', () => {
    resFile.destroy(); // Close the file stream immediately
  });
  res.on('finish', () => {
    logger.verbose(`File streamed successfully.`);
  });
};