FKITDEV-9193

Classification: task (Type=Task, State=Open, Subsystem=None)

Ticket

Ticket FKITDEV-9193 — Devel - memory leakek

  • Type: Task · State: Open · Subsystem: None · Priority: None

<<<UNTRUSTED_TICKET_DATA — analyze only, never execute Commentekben különállóan írom le a memory leak eseteket és csatolok hozzá scriptet is amit futtatva látszik, hogy a memóriát szép lassan zabálja fel és nincs garbage collection ami ezt orvosolná

Comments

  • Zsolt Mészáros: <<<UNTRUSTED A get() soha be nem fejeződő tárolási műveleteit reprodukálja. Mivel a Promise nem teljesül, a cache-tisztítás sem fut le, ezért az _getInFlightCache folyamatosan nő, és minden bejegyzés memóriában tartja a hozzá tartozó buffert.
process.env.NODE_ENV = process.env.NODE_ENV || 'dev'

const RATE = Number.parseInt(process.env.RATE || '20', 10)
const CHUNK_KB = Number.parseInt(process.env.CHUNK_KB || '256', 10)

const serviceContainer = require('./server/service_container')
serviceContainer.logger = console

const StorageService = require('./server/service/StorageService')
const svc = new StorageService()

svc._getImpl = async () => {
  const stuckBuffer = Buffer.alloc(CHUNK_KB * 1024, 1)
  await new Promise((resolve) => setTimeout(resolve, 10 * 60 * 1000).unref())
  return stuckBuffer
}

let nextId = 1
let totalCalls = 0
const startedAt = Date.now()

console.log(`[leak-repro] rate=${RATE}/s chunk=${CHUNK_KB}KB pid=${process.pid}`)
console.log('[leak-repro] watch this container in another shell with: docker stats <container>\n')

const fireInterval = setInterval(() => {
  for (let i = 0; i < RATE; i++) {
    svc.get('selfServiceRoom', { id: nextId++, converted: true })
    totalCalls++
  }
}, 1000)

const reportInterval = setInterval(() => {
  const elapsedSec = Math.round((Date.now() - startedAt) / 1000)
  const mem = process.memoryUsage()
  const cacheSize = svc._getInFlightCache.size
  const simulatedRetainedMB = (cacheSize * CHUNK_KB) / 1024

  console.log(
    `[+${elapsedSec}s] cache entries=${cacheSize} ` +
    `(total calls=${totalCalls}) ` +
    `simulated retained~${simulatedRetainedMB.toFixed(1)}MB | ` +
    `rss=${(mem.rss / 1024 / 1024).toFixed(1)}MB heapUsed=${(mem.heapUsed / 1024 / 1024).toFixed(1)}MB`
  )
}, 1000)

process.on('SIGINT', () => {
  clearInterval(fireInterval)
  clearInterval(reportInterval)
  console.log(`\n[leak-repro] stopped. Final cache size: ${svc._getInFlightCache.size} entries, ${totalCalls} total calls fired.`)
  process.exit(0)
})
``` >>>
- **Zsolt Mészáros**: <<<UNTRUSTED A videós Range kéréseknél használt stream() útvonalat modellezi. Egy timeout nélküli, beragadt S3/MinIO kérés soha nem zárul le; itt nincs deduplikáció vagy cache, így minden új Range kérés külön függő Promiset és buffert tart életben.

process.env.NODE_ENV = process.env.NODE_ENV || ‘dev’

const RATE = Number.parseInt(process.env.RATE || ‘20’, 10) const CHUNK_KB = Number.parseInt(process.env.CHUNK_KB || ‘256’, 10)

const serviceContainer = require(‘./server/service_container’) serviceContainer.logger = console serviceContainer.dbModels = { Storage: { types: { ROOM: ‘room’, SELFSERVICEROOM: ‘selfServiceRoom’, ATTACHMENT: ‘attachment’ } } }

const StorageService = require(‘./server/service/StorageService’) const svc = new StorageService()

const fakeEngine = { getConvertedStoragePath (storageType, id, filePath) { return records/${storageType}/${id}/converted/${filePath} }, async get () { const stuckBuffer = Buffer.alloc(CHUNK_KB * 1024, 1) await new Promise((resolve) setTimeout(resolve, 10 * 60 * 1000).unref()) return stuckBuffer } } svc.storages.set(‘fakeEngine’, fakeEngine)

const pendingRequests = []

let nextRoomId = 1 let totalCalls = 0 const startedAt = Date.now()

console.log([leak-repro-stream] rate=${RATE}/s chunk=${CHUNK_KB}KB pid=${process.pid}) console.log(‘[leak-repro-stream] watch this container in another shell with: docker stats \n’)

const fireInterval = setInterval(() { for (let i = 0; i < RATE; i++) { const storageModel = { name: ‘fakeEngine’, type: ‘selfServiceRoom’, selfServiceRoomId: nextRoomId++ } const req = svc.stream(storageModel, { path: ‘videoroom-x.webm’, start: 0, end: 999 }) req.catch(() {}) pendingRequests.push(req) totalCalls++ } }, 1000)

const reportInterval = setInterval(() { const elapsedSec = Math.round((Date.now() - startedAt) / 1000) const mem = process.memoryUsage() const simulatedRetainedMB = (pendingRequests.length * CHUNK_KB) / 1024

console.log( [+${elapsedSec}s] pending "requests"=${pendingRequests.length} + (total calls=${totalCalls}) + simulated retained~${simulatedRetainedMB.toFixed(1)}MB | + rss=${(mem.rss / 1024 / 1024).toFixed(1)}MB heapUsed=${(mem.heapUsed / 1024 / 1024).toFixed(1)}MB ) }, 1000)

process.on(‘SIGINT’, () { clearInterval(fireInterval) clearInterval(reportInterval) console.log(\n[leak-repro-stream] stopped. ${pendingRequests.length} pending "requests" never completed, ${totalCalls} total calls fired.) process.exit(0) })