feat(preview-service): use axios for proper timeout support (#2939)
This commit is contained in:
Родитель
1908e978fe
Коммит
965c9f94f6
|
@ -58,7 +58,7 @@ RUN apt-get update && \
|
|||
RUN apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y \
|
||||
--no-install-recommends \
|
||||
google-chrome-stable=128.0.6613.119-1 \
|
||||
google-chrome-stable=128.0.6613.137-1 \
|
||||
fonts-ipafont-gothic=00303-23 \
|
||||
fonts-wqy-zenhei=0.9.45-8 \
|
||||
fonts-thai-tlwg=1:0.7.3-1 \
|
||||
|
@ -104,4 +104,4 @@ RUN groupadd -g 30000 -r pptruser && \
|
|||
# Run everything after as non-privileged user.
|
||||
USER pptruser
|
||||
|
||||
ENTRYPOINT [ "tini", "--", "node", "--loader=./dist/src/aliasLoader.js", "bin/www" ]
|
||||
ENTRYPOINT [ "tini", "--", "node", "--loader=./dist/src/aliasLoader.js", "bin/www.js" ]
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
"scripts": {
|
||||
"build:tsc:watch": "tsc -p ./tsconfig.build.json --watch",
|
||||
"build:webpack:watch": "webpack --env build --config webpack.config.renderPage.cjs --watch",
|
||||
"run:watch": "NODE_ENV=development LOG_PRETTY=true LOG_LEVEL=debug nodemon --exec \"yarn start\" --trace-deprecation --watch ./bin/www --watch ./dist",
|
||||
"run:watch": "NODE_ENV=development LOG_PRETTY=true LOG_LEVEL=debug nodemon --exec \"yarn start\" --trace-deprecation --watch ./bin/www.js --watch ./dist",
|
||||
"dev": "concurrently \"npm:build:tsc:watch\" \"npm:build:webpack:watch\" \"npm:run:watch\"",
|
||||
"dev:headed": "PREVIEWS_HEADED=true yarn dev",
|
||||
"build:tsc": "rimraf ./dist/src && tsc -p ./tsconfig.build.json",
|
||||
|
@ -27,7 +27,7 @@
|
|||
"lint:ci": "yarn lint:tsc",
|
||||
"lint:tsc": "tsc --noEmit",
|
||||
"lint:eslint": "eslint .",
|
||||
"start": "node --loader=./dist/src/aliasLoader.js ./bin/www",
|
||||
"start": "node --loader=./dist/src/aliasLoader.js ./bin/www.js",
|
||||
"test": "NODE_ENV=test LOG_LEVEL=silent LOG_PRETTY=true vitest run --sequence.shuffle --exclude 'tests/acceptance/**/*.spec.ts'",
|
||||
"test:acceptance": "NODE_ENV=test LOG_LEVEL=debug LOG_PRETTY=true vitest run 'tests/acceptance/acceptance.spec.ts' --sequence.shuffle --hookTimeout 60000 --testNamePattern 'Acceptance'"
|
||||
},
|
||||
|
@ -35,6 +35,7 @@
|
|||
"@speckle/objectloader": "workspace:^",
|
||||
"@speckle/shared": "workspace:^",
|
||||
"@speckle/viewer": "workspace:^",
|
||||
"axios": "^1.7.7",
|
||||
"cookie-parser": "~1.4.4",
|
||||
"crypto": "^1.0.1",
|
||||
"dotenv": "^16.4.5",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import type { Angle, ObjectIdentifier } from '@/domain/domain.js'
|
||||
import { isCastableToBrand } from '@/utils/brand.js'
|
||||
import axios from 'axios'
|
||||
import { z } from 'zod'
|
||||
|
||||
const previewResponseSchema = z.record(
|
||||
|
@ -12,11 +13,16 @@ export type GeneratePreview = (
|
|||
) => Promise<Record<Angle, string | undefined>>
|
||||
|
||||
export const generatePreviewFactory =
|
||||
(deps: { serviceOrigin: string }): GeneratePreview =>
|
||||
({
|
||||
serviceOrigin,
|
||||
timeout
|
||||
}: {
|
||||
serviceOrigin: string
|
||||
timeout: number
|
||||
}): GeneratePreview =>
|
||||
async (task: ObjectIdentifier) => {
|
||||
const previewUrl = `${deps.serviceOrigin}/preview/${task.streamId}/${task.objectId}`
|
||||
const response = await fetch(previewUrl)
|
||||
const responseBody: unknown = await response.json()
|
||||
const previewResponse = previewResponseSchema.parse(responseBody)
|
||||
const previewUrl = `${serviceOrigin}/preview/${task.streamId}/${task.objectId}`
|
||||
const res = await axios.get(previewUrl, { timeout })
|
||||
const previewResponse = previewResponseSchema.parse(res.data)
|
||||
return previewResponse
|
||||
}
|
||||
|
|
|
@ -15,7 +15,11 @@ import { insertPreviewFactory } from '@/repositories/previews.js'
|
|||
import { generateAndStore360PreviewFactory } from '@/services/360preview.js'
|
||||
import { pollForAndCreatePreviewFactory } from '@/services/pollForPreview.js'
|
||||
import { forceExit, repeatedlyDoSomeWorkFactory } from '@/services/taskManager.js'
|
||||
import { getHealthCheckFilePath, serviceOrigin } from '@/utils/env.js'
|
||||
import {
|
||||
getHealthCheckFilePath,
|
||||
serviceOrigin,
|
||||
getPreviewTimeout
|
||||
} from '@/utils/env.js'
|
||||
import type { Knex } from 'knex'
|
||||
|
||||
export function startPreviewService(params: { db: Knex }) {
|
||||
|
@ -41,7 +45,10 @@ export function startPreviewService(params: { db: Knex }) {
|
|||
}),
|
||||
getNextUnstartedObjectPreview: getNextUnstartedObjectPreviewFactory({ db }),
|
||||
generateAndStore360Preview: generateAndStore360PreviewFactory({
|
||||
generatePreview: generatePreviewFactory({ serviceOrigin: serviceOrigin() }),
|
||||
generatePreview: generatePreviewFactory({
|
||||
serviceOrigin: serviceOrigin(),
|
||||
timeout: getPreviewTimeout()
|
||||
}),
|
||||
insertPreview: insertPreviewFactory({ db })
|
||||
}),
|
||||
updatePreviewMetadata: updatePreviewMetadataFactory({ db }),
|
||||
|
|
|
@ -32,6 +32,12 @@ export const pollForAndCreatePreviewFactory =
|
|||
if (!task) {
|
||||
return WorkStatus.NOWORKFOUND
|
||||
}
|
||||
const logger = deps.logger.child({
|
||||
projectId: task.streamId,
|
||||
objectId: task.objectId
|
||||
})
|
||||
|
||||
logger.info('Found next preview task for {projectId}/{objectId}')
|
||||
|
||||
let metricDurationEnd:
|
||||
| (<T extends string>(labels?: LabelValues<T>) => number)
|
||||
|
@ -48,15 +54,24 @@ export const pollForAndCreatePreviewFactory =
|
|||
streamId: task.streamId,
|
||||
objectId: task.objectId
|
||||
})
|
||||
logger.info(
|
||||
{ previewStatus: 'succeeded' },
|
||||
'Preview generation completed. Status: {previewStatus}'
|
||||
)
|
||||
|
||||
await deps.notifyUpdate({ streamId: task.streamId, objectId: task.objectId })
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
{ err, previewStatus: 'failed' },
|
||||
'Preview generation completed. Status: {previewStatus}'
|
||||
)
|
||||
await deps.updatePreviewMetadata({
|
||||
metadata: { err: err instanceof Error ? err.message : JSON.stringify(err) },
|
||||
streamId: task.streamId,
|
||||
objectId: task.objectId
|
||||
})
|
||||
metricOperationErrors?.labels('preview').inc()
|
||||
return WorkStatus.FAILED
|
||||
}
|
||||
if (metricDurationEnd) {
|
||||
metricDurationEnd({ op: 'preview' })
|
||||
|
|
12
yarn.lock
12
yarn.lock
|
@ -15351,6 +15351,7 @@ __metadata:
|
|||
"@types/lodash-es": "npm:^4.17.6"
|
||||
"@types/node": "npm:^18.19.38"
|
||||
"@vitest/coverage-istanbul": "npm:^1.6.0"
|
||||
axios: "npm:^1.7.7"
|
||||
babel-loader: "npm:^8.2.2"
|
||||
clean-webpack-plugin: "npm:^4.0.0-alpha.0"
|
||||
concurrently: "npm:^8.2.2"
|
||||
|
@ -23342,6 +23343,17 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"axios@npm:^1.7.7":
|
||||
version: 1.7.7
|
||||
resolution: "axios@npm:1.7.7"
|
||||
dependencies:
|
||||
follow-redirects: "npm:^1.15.6"
|
||||
form-data: "npm:^4.0.0"
|
||||
proxy-from-env: "npm:^1.1.0"
|
||||
checksum: 10/7f875ea13b9298cd7b40fd09985209f7a38d38321f1118c701520939de2f113c4ba137832fe8e3f811f99a38e12c8225481011023209a77b0c0641270e20cde1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"b4a@npm:^1.6.4":
|
||||
version: 1.6.4
|
||||
resolution: "b4a@npm:1.6.4"
|
||||
|
|
Загрузка…
Ссылка в новой задаче