Update objectpreview on error
- use const with explanatory variable names
This commit is contained in:
@@ -33,7 +33,11 @@ export const jobProcessor = async ({
|
||||
port,
|
||||
timeout
|
||||
}: JobArgs): Promise<PreviewResultPayload> => {
|
||||
const start = new Date()
|
||||
const elapsed = (() => {
|
||||
const start = new Date().getTime()
|
||||
return () => (new Date().getTime() - start) / 1000
|
||||
})()
|
||||
|
||||
logger.info('Picked up job {jobId} for {serverUrl}')
|
||||
|
||||
const jobMessage =
|
||||
@@ -43,12 +47,10 @@ export const jobProcessor = async ({
|
||||
page = await browser.newPage()
|
||||
|
||||
const result = await pageFunction({ page, job, logger, port, timeout })
|
||||
const elapsed = (new Date().getTime() - start.getTime()) / 1000
|
||||
logger.info({ status: result.status, elapsed }, jobMessage)
|
||||
logger.info({ status: result.status, elapsed: elapsed() }, jobMessage)
|
||||
return result
|
||||
} catch (err: unknown) {
|
||||
const elapsed = (new Date().getTime() - start.getTime()) / 1000
|
||||
logger.error({ err, elapsed, status: 'error' }, jobMessage)
|
||||
logger.error({ err, elapsed: elapsed(), status: 'error' }, jobMessage)
|
||||
const reason =
|
||||
err instanceof Error
|
||||
? err.stack ?? err.toString()
|
||||
@@ -60,7 +62,7 @@ export const jobProcessor = async ({
|
||||
jobId: job.jobId,
|
||||
status: 'error',
|
||||
result: {
|
||||
durationSeconds: elapsed
|
||||
durationSeconds: elapsed()
|
||||
},
|
||||
reason
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
export const PreviewStatus = {
|
||||
PENDING: 0,
|
||||
PROCESSING: 1,
|
||||
DONE: 2,
|
||||
ERROR: 3
|
||||
} as const
|
||||
|
||||
export const PreviewPriority = {
|
||||
LOW: 0,
|
||||
MEDIUM: 100,
|
||||
HIGH: 200
|
||||
} as const
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ObjectPreview } from '@/modules/previews/domain/types'
|
||||
import { Nullable, Optional } from '@speckle/shared'
|
||||
import express from 'express'
|
||||
import type { ObjectPreview } from '@/modules/previews/domain/types'
|
||||
import type { Nullable, Optional, PartialBy } from '@speckle/shared'
|
||||
import type { Request, Response } from 'express'
|
||||
|
||||
export type GetObjectPreviewInfo = (params: {
|
||||
streamId: string
|
||||
@@ -17,7 +17,7 @@ export type ObjectPreviewInput = Pick<
|
||||
>
|
||||
export type StoreObjectPreview = (params: ObjectPreviewInput) => Promise<void>
|
||||
export type UpsertObjectPreview = (params: {
|
||||
objectPreview: ObjectPreview
|
||||
objectPreview: PartialBy<ObjectPreview, 'preview' | 'priority'>
|
||||
}) => Promise<void>
|
||||
|
||||
export type ObjectPreviewRequest = {
|
||||
@@ -54,13 +54,13 @@ export type GetObjectPreviewBufferOrFilepath = (params: {
|
||||
>
|
||||
|
||||
export type SendObjectPreview = (
|
||||
req: express.Request,
|
||||
res: express.Response,
|
||||
req: Request,
|
||||
res: Response,
|
||||
streamId: string,
|
||||
objectId: string,
|
||||
angle?: string
|
||||
) => Promise<void>
|
||||
|
||||
export type CheckStreamPermissions = (
|
||||
req: express.Request
|
||||
req: Request
|
||||
) => Promise<{ hasPermissions: boolean; httpErrorCode: number }>
|
||||
|
||||
@@ -70,7 +70,10 @@ const getPreviewQueues = (params: { responseQueueName: string }) => {
|
||||
|
||||
// previews are requested on this queue
|
||||
const previewRequestQueue = new Bull('preview-service-jobs', opts)
|
||||
addRequestQueueListeners({ logger, previewRequestQueue })
|
||||
addRequestQueueListeners({
|
||||
logger,
|
||||
previewRequestQueue
|
||||
})
|
||||
|
||||
// rendered previews are sent back on this queue
|
||||
const previewResponseQueue = new Bull(responseQueueName, opts)
|
||||
|
||||
@@ -2,6 +2,9 @@ import type { RequestObjectPreview } from '@/modules/previews/domain/operations'
|
||||
import type { Logger } from '@/observability/logging'
|
||||
import type { Queue, Job } from 'bull'
|
||||
import type { EventEmitter } from 'stream'
|
||||
import { upsertObjectPreviewFactory } from '@/modules/previews/repository/previews'
|
||||
import { getProjectDbClient } from '@/modules/multiregion/utils/dbSelector'
|
||||
import { PreviewStatus } from '@/modules/previews/domain/consts'
|
||||
|
||||
export const requestObjectPreviewFactory =
|
||||
({
|
||||
@@ -30,9 +33,20 @@ export const addRequestQueueListeners = (params: {
|
||||
previewRequestQueue.removeListener('error', requestErrorHandler)
|
||||
previewRequestQueue.on('error', requestErrorHandler)
|
||||
|
||||
const requestFailedHandler = (job: Job, err: Error) => {
|
||||
const requestFailedHandler = async (job: Job, err: Error) => {
|
||||
const jobId = 'jobId' in job.data ? job.data.jobId : undefined
|
||||
logger.error({ err, jobId }, 'Preview job {jobId} failed.')
|
||||
if (!jobId) return
|
||||
const [projectId, objectId] = jobId.split('.')
|
||||
const projectDb = await getProjectDbClient({ projectId })
|
||||
upsertObjectPreviewFactory({ db: projectDb })({
|
||||
objectPreview: {
|
||||
streamId: projectId,
|
||||
objectId,
|
||||
previewStatus: PreviewStatus.ERROR,
|
||||
lastUpdate: new Date()
|
||||
}
|
||||
})
|
||||
}
|
||||
previewRequestQueue.removeListener('failed', requestFailedHandler)
|
||||
previewRequestQueue.on('failed', requestFailedHandler)
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
} from '@/modules/previews/domain/types'
|
||||
import { Knex } from 'knex'
|
||||
import { SetOptional } from 'type-fest'
|
||||
import { PreviewStatus } from '@/modules/previews/domain/consts'
|
||||
|
||||
const ObjectPreview = buildTableHelper('object_preview', [
|
||||
'streamId',
|
||||
@@ -53,7 +54,7 @@ export const storeObjectPreviewFactory =
|
||||
streamId,
|
||||
objectId,
|
||||
priority,
|
||||
previewStatus: 0
|
||||
previewStatus: PreviewStatus.PENDING
|
||||
}
|
||||
const sqlQuery = tables.objectPreview(db).insert(insertionObject)
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import crypto from 'crypto'
|
||||
import { StorePreview, UpsertObjectPreview } from '@/modules/previews/domain/operations'
|
||||
import { joinImages } from 'join-images'
|
||||
import { GetObjectCommitsWithStreamIds } from '@/modules/core/domain/commits/operations'
|
||||
import { PreviewPriority, PreviewStatus } from '@/modules/previews/domain/consts'
|
||||
|
||||
const payloadRegexp = /^([\w\d]+):([\w\d]+):([\w\d]+)$/i
|
||||
|
||||
@@ -70,8 +71,7 @@ export const consumePreviewResultFactory =
|
||||
}) => {
|
||||
const streamId = projectId
|
||||
const lastUpdate = new Date()
|
||||
const priority = 0
|
||||
const previewStatus = 2
|
||||
const priority = PreviewPriority.LOW
|
||||
const log = logger.child({
|
||||
jobId: previewResult.jobId,
|
||||
status: previewResult.status,
|
||||
@@ -92,7 +92,7 @@ export const consumePreviewResultFactory =
|
||||
lastUpdate,
|
||||
preview: { err: previewResult.reason },
|
||||
priority,
|
||||
previewStatus
|
||||
previewStatus: PreviewStatus.ERROR
|
||||
}
|
||||
})
|
||||
break
|
||||
@@ -141,7 +141,7 @@ export const consumePreviewResultFactory =
|
||||
lastUpdate,
|
||||
preview,
|
||||
priority,
|
||||
previewStatus
|
||||
previewStatus: PreviewStatus.DONE
|
||||
}
|
||||
})
|
||||
const commits = await getObjectCommitsWithStreamIds([objectId], {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { authorizeResolver, validateScopes } from '@/modules/shared'
|
||||
import { disablePreviews } from '@/modules/shared/helpers/envHelper'
|
||||
import { Roles, Scopes } from '@speckle/shared'
|
||||
import type { Logger } from 'pino'
|
||||
import { PreviewPriority, PreviewStatus } from '@/modules/previews/domain/consts'
|
||||
|
||||
const noPreviewImage = require.resolve('#/assets/previews/images/no_preview.png')
|
||||
const previewErrorImage = require.resolve('#/assets/previews/images/preview_error.png')
|
||||
@@ -54,12 +55,16 @@ export const getObjectPreviewBufferOrFilepathFactory =
|
||||
const objPreviewQueued = await deps.createObjectPreview({
|
||||
streamId,
|
||||
objectId,
|
||||
priority: 0
|
||||
priority: PreviewPriority.LOW
|
||||
})
|
||||
if (!objPreviewQueued) return { type: 'file', file: noPreviewImage }
|
||||
}
|
||||
|
||||
if (!previewInfo || previewInfo.previewStatus !== 2 || !previewInfo.preview) {
|
||||
if (
|
||||
!previewInfo ||
|
||||
previewInfo.previewStatus !== PreviewStatus.DONE ||
|
||||
!previewInfo.preview
|
||||
) {
|
||||
return { type: 'file', file: noPreviewImage }
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ export type PartialNullable<T> = {
|
||||
[K in keyof T]?: T[K] | null
|
||||
}
|
||||
|
||||
export type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
|
||||
|
||||
type NullableKeys<T> = {
|
||||
[K in keyof T]: T[K] extends NonNullable<T[K]> ? never : K
|
||||
}[keyof T]
|
||||
|
||||
Reference in New Issue
Block a user