Процесс работает 2 дня в итоге pm2 показывает 1350MB используемой памяти (трафик ~1500 хостов в сутки)
Структура основных файлов роутера
Не пойму где утечка, может быть и не тут, ищу уже неделю, предположения только из за saveCache(e), может ее на промисы подключить для параллельного выполнения с result?
const URL = require('url')
, config = require('../configs')
, score = require('../libs/score')
, ObjectId = require('mongodb').ObjectId
, HttpError = require('../libs/error').HttpError
, Cache = require('../collections/cache').Cache
, Posts = require('../collections/posts').Posts
exports.get = (request, response, next) => {
request.href = `${request.protocol}://${request.get('host')}${request.originalUrl}`
request.uid = request.user && request.user._id || ObjectId()
const makeRequest = async () => {
const e = {};
const cache = await getCache(request, response)
if(null !== cache) return
e.params = await getParams(request)
e.items = await getDocuments(e.params)
return result(e, response), saveCache(e)
}
return makeRequest()
.catch(e => {
return next(new HttpError(404, e.message))
})
}
/**
* Get cache page href
* @param {*} request - href
*/
function getCache(request, response) {
const href = new URL.URL(request.href)
const format = +!!href.searchParams.get('format')
href.searchParams.delete('seed')
href.searchParams.delete('format')
return Cache.findOne({ href: href }).exec()
.then(e => {
if(e) {
e = JSON.parse(e.cache)
e.score = score
e.config = config
e.params.sessionId = request.uid
}
return e ? (format && response.end(HTML(e)) || response.render('index', e)) : null
}).catch(e => {
throw new Error(e.message);
})
}
/**
* Сбор данных
* @param {*} request
*/
function getParams(request) {
const cleanHref = new URL.URL(request.href)
const format = +!!cleanHref.searchParams.get('format')
cleanHref.searchParams.delete('seed')
cleanHref.searchParams.delete('format')
return {
local: request.local,
type: 'index',
format: format,
href: request.href,
cleanHref: cleanHref,
limit: config.count.photos,
page: +cleanHref.searchParams.get('page') || 0,
sessionId: request.user && request.user._id || ObjectId(),
skip: !!parseInt(request.query.page) && (request.query.page - 1) * config.count.photos || 0
}
}
/**
* Get documents
* @param {*} request
*/
function getDocuments(request) {
return Posts
.aggregate([
{ $match: { catalog: { $nin: config.catalogs }, public: { $gte: 2 } } },
{ $sort: { indexAt: -1 } },
{ $skip: request.skip },
{ $limit: request.limit },
{
$lookup: {
from: 'users',
localField: 'owner',
foreignField: '_id',
as: 'owner'
}
}, {
$project: {
_id: 1,
image: { $concat: ['$domain', 'o/', '$image', '?route=thumb&h=350'] },
href: { $concat: [config.domain.href, 'posts/', '$url', '.html'] },
tags: { $slice: ['$tags', 5] },
size: {
width: { $trunc: { $multiply: [ { $divide: ['$size.width', '$size.height'] }, 350] } },
height: { $trunc: 350 }
},
style: {
$concat: [
'background-color: rgb(',
{ $toLower: { $arrayElemAt: [ '$pixels.rgb.r', 0 ] } }, ',',
{ $toLower: { $arrayElemAt: [ '$pixels.rgb.g', 0 ] } }, ',',
{ $toLower: { $arrayElemAt: [ '$pixels.rgb.b', 0 ] } }, ')'
]
},
owner: { $arrayElemAt: [ '$owner', 0 ] },
//likes: { $in: [request.sessionId, '$likes'] }, // не работает правильно с кешированием
likes: 1,
indexAt: 1
}
}, {
$group: {
_id: "$_id",
image: { $first: '$image' },
href: { $first: '$href' },
tags: { $first: '$tags' },
size: { $first: '$size' },
style: { $first: '$style' },
owner: { $first: {
_id: '$owner._id',
name: '$owner.name',
avatar: { $concat: ['background-image:url(', '$owner.avatar', ')'] },
href: { $concat: [config.domain.href, '$owner.username', '/'] }
} },
likes: { $first: '$likes' },
indexAt: { $first: '$indexAt' }
}
}, {
$sort: { indexAt: -1 }
}
])
.exec()
.then(e => {
return e;
})
.catch(e => {
throw new Error(e);
})
}
/**
* Result
* @param {*} request
* @param {*} response
*/
function result(request, response) {
request.seed = new Date()
request.cover = 1
request.score = score
request.config = config
request.pagination = score.pagination({ count: request.items.length, href: request.params.href, limit: config.count.photos })
request.page = {
name: request.params.page ? request.params.local.pagination + request.params.page : request.params.local.name,
description: request.params.local.description,
keywords: request.params.local.keywords
}
return request.params.format && response.end(HTML(request)) || response.render('index', request)
//return response.send(request)
}
/**
* Write cache
* @param {*} request
*/
function saveCache(request) {
return new Cache( { href: request.params.cleanHref, cache: JSON.stringify(request), type: request.params.type } ).save()
}
function HTML(request) {
// Тут динамическая подгрузка данных
}