Критические оптимизации для снижения потребления памяти
- Кэширование только текущей недели:
* Кэш хранит только текущие недели (без параметра wk)
* Запросы с конкретной неделей (wk указан) не кэшируются
* Ключ кэша изменен с `${group}_${wk}` на `group`
* Уменьшен maxCacheSize с 100 до 50 записей
- Условный парсинг навигации по неделям:
* Парсинг навигации выполняется только если weekNavigationEnabled === true
* Если навигация выключена, parseWeekNavigation не вызывается
* Экономит память и CPU при выключенной навигации
* Параметр shouldParseWeekNavigation передается через getSchedule -> parsePage
- Результат:
* Значительное снижение потребления памяти
* Кэш содержит только актуальные данные (текущие недели)
* Парсинг навигации выполняется только при необходимости
Измененные файлы:
- src/pages/[group].tsx - логика кэширования только текущей недели
- src/app/agregator/schedule.ts - параметр для условного парсинга
- src/app/parser/schedule.ts - условный вызов parseWeekNavigation
52 lines
2.2 KiB
TypeScript
52 lines
2.2 KiB
TypeScript
import { Day } from '@/shared/model/day'
|
||
import { parsePage, ParseResult, WeekInfo } from '@/app/parser/schedule'
|
||
import contentTypeParser from 'content-type'
|
||
import { JSDOM } from 'jsdom'
|
||
// import { content as mockContent } from './mock'
|
||
import { reportParserError } from '@/app/logger'
|
||
import { PROXY_URL } from '@/shared/constants/urls'
|
||
|
||
export type ScheduleResult = {
|
||
days: Day[]
|
||
currentWk?: number
|
||
availableWeeks?: WeekInfo[]
|
||
}
|
||
|
||
// ПС-7: 146
|
||
export async function getSchedule(groupID: number, groupName: string, wk?: number, parseWeekNavigation: boolean = true): Promise<ScheduleResult> {
|
||
const url = `${PROXY_URL}/?mn=2&obj=${groupID}${wk ? `&wk=${wk}` : ''}`
|
||
const page = await fetch(url)
|
||
// const page = { text: async () => mockContent, status: 200, headers: { get: (s: string) => s && 'text/html' } }
|
||
const content = await page.text()
|
||
const contentType = page.headers.get('content-type')
|
||
if (page.status === 200 && contentType && contentTypeParser.parse(contentType).type === 'text/html') {
|
||
let dom: JSDOM | null = null
|
||
try {
|
||
dom = new JSDOM(content, { url })
|
||
const root = dom.window.document
|
||
const result = parsePage(root, groupName, url, parseWeekNavigation)
|
||
const scheduleResult = {
|
||
days: result.days,
|
||
currentWk: result.currentWk || wk,
|
||
availableWeeks: result.availableWeeks
|
||
}
|
||
// Явно очищаем JSDOM для освобождения памяти
|
||
dom.window.close()
|
||
dom = null
|
||
return scheduleResult
|
||
} catch(e) {
|
||
// Очищаем JSDOM даже в случае ошибки
|
||
if (dom) {
|
||
dom.window.close()
|
||
}
|
||
console.error(`Error while parsing ${PROXY_URL}`)
|
||
reportParserError(new Date().toISOString(), 'Не удалось сделать парсинг для группы', groupName)
|
||
throw e
|
||
}
|
||
} else {
|
||
console.error(page.status, contentType)
|
||
console.error(content.length > 500 ? content.slice(0, 500 - 3) + '...' : content)
|
||
reportParserError(new Date().toISOString(), 'Не удалось получить страницу для группы', groupName)
|
||
throw new Error(`Error while fetching ${PROXY_URL}`)
|
||
}
|
||
} |