Memoize loadRedirects() with disk (#22161)

* memoize loadRedirects with disk in development

* no need to await on sync functions

* un-uncomment

* wip

* wip

* cache with max age

* rename redirects memoize cache file
This commit is contained in:
Peter Bengtsson 2021-10-22 11:25:32 -04:00 коммит произвёл GitHub
Родитель 711bd22f02
Коммит da419fd869
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 47 добавлений и 16 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -15,3 +15,4 @@ coverage/
blc_output.log blc_output.log
blc_output_internal.log blc_output_internal.log
broken_links.md broken_links.md
lib/redirects/.redirects-cache_*.json

Просмотреть файл

@ -1,22 +1,53 @@
import { languageKeys } from '../languages.js' import assert from 'assert'
import fs from 'fs/promises'
import path from 'path'
import { isPromise } from 'util/types'
import { fileURLToPath } from 'url'
import readJsonFile from '../read-json-file.js' import readJsonFile from '../read-json-file.js'
import { latest } from '../../lib/enterprise-server-releases.js' import { latest } from '../../lib/enterprise-server-releases.js'
import getExceptionRedirects from './exception-redirects.js' import getExceptionRedirects from './exception-redirects.js'
const developerRedirects = readJsonFile('./lib/redirects/static/developer.json') import { languageKeys } from '../languages.js'
const latestDevRedirects = {}
// Replace hardcoded 'latest' with real value in the redirected path function diskMemoize(filePath, asyncFn, maxAgeSeconds = 60 * 60) {
Object.entries(developerRedirects).forEach(([oldPath, newPath]) => { return async (...args) => {
latestDevRedirects[oldPath] = newPath.replace( try {
'enterprise-server@latest', const stats = await fs.stat(filePath)
`enterprise-server@${latest}` const ageSeconds = (new Date().getTime() - stats.mtime.getTime()) / 1000
) if (ageSeconds < maxAgeSeconds) {
}) const value = JSON.parse(await fs.readFile(filePath, 'utf-8'))
console.log(`Redirects disk-cache HIT on ${filePath}`)
return value
}
console.log(`Redirects disk-cache ${filePath} too old`)
} catch (err) {
if (err.code !== 'ENOENT') throw err
}
console.log(`Redirects disk-cache MISS on ${filePath}`)
const promise = asyncFn(...args)
assert(isPromise(promise), "memoized function didn't return a promise")
return promise.then(async (value) => {
await fs.writeFile(filePath, JSON.stringify(value), 'utf-8')
return value
})
}
}
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const DISK_CACHE_FILEPATH = path.join(__dirname, `.redirects-cache_${languageKeys.join('_')}.json`)
// This function runs at server warmup and precompiles possible redirect routes. // This function runs at server warmup and precompiles possible redirect routes.
// It outputs them in key-value pairs within a neat Javascript object: { oldPath: newPath } // It outputs them in key-value pairs within a neat Javascript object: { oldPath: newPath }
export default async function precompileRedirects(pageList) { const precompileRedirects = diskMemoize(DISK_CACHE_FILEPATH, async (pageList) => {
const allRedirects = Object.assign({}, latestDevRedirects) const allRedirects = readJsonFile('./lib/redirects/static/developer.json')
// Replace hardcoded 'latest' with real value in the redirected path
Object.entries(allRedirects).forEach(([oldPath, newPath]) => {
allRedirects[oldPath] = newPath.replace(
'enterprise-server@latest',
`enterprise-server@${latest}`
)
})
// Exception redirects are those that are essentially unicorn one-offs. // Exception redirects are those that are essentially unicorn one-offs.
// For example, we have redirects for documents that used to be on // For example, we have redirects for documents that used to be on
@ -35,9 +66,8 @@ export default async function precompileRedirects(pageList) {
// CURRENT PAGES PERMALINKS AND FRONTMATTER // CURRENT PAGES PERMALINKS AND FRONTMATTER
// create backwards-compatible old paths for page permalinks and frontmatter redirects // create backwards-compatible old paths for page permalinks and frontmatter redirects
await Promise.all( pageList.forEach((page) => Object.assign(allRedirects, page.buildRedirects()))
pageList.map(async (page) => Object.assign(allRedirects, page.buildRedirects()))
)
return allRedirects return allRedirects
} })
export default precompileRedirects