Skip to content

Commit b96f3df

Browse files
ElderMattsvcAPLBot
andauthored
feat: added caching for the BYO Catalog (#949)
* feat: added caching for byo catalog * fix: deleted object files * feat: return object when successfully refreshed and testing 1 minute refresh * fix: tests * fix: change clone strategy * fix: tests * feat: create and edit catalog change to void for getbyoworkloadcatalog * feat: enabled caching check for sparsecheckout * fix: remove commented lines * feat: remove redundant feature for cloning single chart * chore: change back refresh cache to minutes * fix: removed getworkloadcatalogchart and remove try catch on create catalog * fix: remove sparsecheckoutpath --------- Co-authored-by: svcAPLBot <174728082+svcAPLBot@users.noreply.github.com>
1 parent 6a2aba7 commit b96f3df

8 files changed

Lines changed: 331 additions & 141 deletions

File tree

package-lock.json

Lines changed: 62 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/api/v2/catalogs/refresh.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import Debug from 'debug'
2+
import { Response } from 'express'
3+
import { BadRequestError } from 'src/error'
4+
import { OpenApiRequestExt } from 'src/otomi-models'
5+
6+
const debug = Debug('otomi:api:v2:catalogs:refresh')
7+
8+
/**
9+
* POST /v2/catalogs/refresh
10+
* Refresh BYO catalog cache(s) immediately
11+
*/
12+
export const refreshAplCatalogCache = async (req: OpenApiRequestExt, res: Response): Promise<void> => {
13+
const catalogId = typeof req.query.catalogId === 'string' ? decodeURIComponent(req.query.catalogId) : undefined
14+
debug(`refreshAplCatalogCache(${catalogId || 'all'})`)
15+
try {
16+
await req.otomi.refreshBYOCatalogCache(catalogId)
17+
res.status(200).json({ code: 200, message: 'Successfully refreshed catalog cache' })
18+
} catch (e) {
19+
debug('refreshAplCatalogCache failed', e)
20+
res.status(400).json(new BadRequestError('Failed to refresh catalog cache'))
21+
}
22+
}

src/app.ts

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { AplResponseObject, OpenAPIDoc, Schema, SealedSecretManifestResponse } f
2424
import { default as OtomiStack } from 'src/otomi-stack'
2525
import { extract, getPaths, getValuesSchema } from 'src/utils'
2626
import {
27+
CATALOG_CACHE_REFRESH_INTERVAL_MS,
2728
CHECK_LATEST_COMMIT_INTERVAL,
2829
cleanEnv,
2930
EXPRESS_PAYLOAD_LIMIT,
@@ -35,6 +36,7 @@ import getLatestRemoteCommitSha from './git/connect'
3536
import { getBuildStatus, getSealedSecretStatus, getServiceStatus, getWorkloadStatus } from './k8s_operations'
3637

3738
const env = cleanEnv({
39+
CATALOG_CACHE_REFRESH_INTERVAL_MS,
3840
CHECK_LATEST_COMMIT_INTERVAL,
3941
EXPRESS_PAYLOAD_LIMIT,
4042
GIT_PUSH_RETRIES,
@@ -146,6 +148,24 @@ export const getAppList = (): string[] => {
146148
return appsSchema.enum as string[]
147149
}
148150

151+
let isCatalogRefreshRunning = false
152+
let catalogRefreshInterval: ReturnType<typeof setInterval> | undefined
153+
154+
export const cloneCatalogRepositories = async (): Promise<void> => {
155+
if (isCatalogRefreshRunning) {
156+
debug('Catalog cache refresh is already running, skipping scheduled run')
157+
return
158+
}
159+
160+
isCatalogRefreshRunning = true
161+
try {
162+
const otomiStack = await getSessionStack()
163+
await otomiStack.refreshBYOCatalogCache()
164+
} finally {
165+
isCatalogRefreshRunning = false
166+
}
167+
}
168+
149169
export async function initApp(inOtomiStack?: OtomiStack) {
150170
// Only create lightship in production (not in tests)
151171
const lightship = env.isTest ? null : createLightship()
@@ -158,7 +178,6 @@ export async function initApp(inOtomiStack?: OtomiStack) {
158178
app.set('trust proxy', env.TRUST_PROXY)
159179
}
160180

161-
const apiRoutesPath = path.resolve(__dirname, 'api')
162181
await loadSpec()
163182
const authz = new Authz(otomiSpec.spec)
164183
app.use(logger('dev'))
@@ -221,14 +240,33 @@ export async function initApp(inOtomiStack?: OtomiStack) {
221240
.listen(PORT, async () => {
222241
debug(`Listening on :::${PORT}`)
223242
lightship?.signalReady()
224-
// Clone repo after the application is ready to avoid Pod NotReady phenomenon, and thus infinite Pod crash loopback
225-
;(await getSessionStack()).initGit()
243+
244+
// Initialize git, warm catalog cache, and then start periodic refresh in one sequenced background task
245+
void (async () => {
246+
const sessionStack = await getSessionStack()
247+
await sessionStack.initGit()
248+
void cloneCatalogRepositories()
249+
250+
if (!catalogRefreshInterval) {
251+
catalogRefreshInterval = setInterval(() => {
252+
void cloneCatalogRepositories().catch((e) => {
253+
debug(e)
254+
})
255+
}, env.CATALOG_CACHE_REFRESH_INTERVAL_MS)
256+
}
257+
})().catch((e) => {
258+
debug(e)
259+
})
226260
})
227261
.on('error', (e) => {
228262
console.error(e)
229263
lightship?.shutdown()
230264
})
231265
lightship?.registerShutdownHandler(() => {
266+
if (catalogRefreshInterval) {
267+
clearInterval(catalogRefreshInterval)
268+
catalogRefreshInterval = undefined
269+
}
232270
;(server as Server).close()
233271
})
234272
}
@@ -271,6 +309,7 @@ export async function initApp(inOtomiStack?: OtomiStack) {
271309

272310
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
273311
app.use('/api-docs/swagger', swaggerUi.serve, swaggerUi.setup(otomiSpec.spec))
312+
274313
return app
275314
}
276315

0 commit comments

Comments
 (0)