From 89abdf7809834a529d9e2db62fe7640262ed8160 Mon Sep 17 00:00:00 2001 From: Daniel Gak Anagrov Date: Thu, 21 Aug 2025 11:08:02 +0200 Subject: [PATCH 1/2] chore: added basic docs to ifc importer service (#5283) --- packages/ifc-import-service/README.md | 39 +++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/ifc-import-service/README.md b/packages/ifc-import-service/README.md index 1e48f7ba5..601fae856 100644 --- a/packages/ifc-import-service/README.md +++ b/packages/ifc-import-service/README.md @@ -2,6 +2,41 @@ This package provides a microservice for importing IFC files in to Speckle. -It is a worker for the queuing system, built on Postgres. +The service was built to be run as a worker, as it will be constantly trying to pick up messages from the `backgroundjob` table specified in `FILEIMPORT_QUEUE_POSTGRES_URL`. Multiple instances of the service can be run in parallel, each instance will process a single job at a time. The queue is built over the concept of `SKIP FOR UPDATE` and transaction isolation levels to avoid race conditions. -It is intended to eventually replace the File Import Service. +## How it works + +Once run the service will look for jobs, it will attempt to download the file and use `open_and_convert_file` from speckleifc to convert the file to a Speckle object. Once its finished, the service does three things: + +1. uploads the file results to the specified speckle server in the job (using speckle python) +2. marks the message as completed/failed (in `backgroundjob`) +3. marks the file import process as completed (via a mutation). + +Some files might cause the service to fail in a controlled or uncontrolled manner, thats why: + +- attempt number must be incremented before the proessing starts in case the processes does not finish. So if a message is picked up that had reached the maximum attempts, it must be marked as failed without trying to process it. +- if a message in a `processing` state reaches the timeout, it can be assumed that the job processing it failed, so it can be picked up again. +- in case of a controlled failure, the service must leave the message in the queue to be retried until the max attempts is reached + +## Usage + +This project uses `Python` over [uv](https://docs.astral.sh/uv/getting-started/installation/). Python does not need to be explicitly installed to use uv. By default, uv will automatically download Python versions when they are required. + +Some examples: + +```bash +# Installation +uv sync # get deps from .toml +uv run python -V # check installation + +# Using tooling +uv run pre-commit run --all-files +uv run ruff format +``` + +To run the service, copy the `.env.example` as `.env` and fill the environment variables. Then use `main.py` as the entrypoint. + +```bash +# Start worker +uv run main.py +``` From fa4784c2d4018cde81a8c6abc2f8c840bb166115 Mon Sep 17 00:00:00 2001 From: Kristaps Fabians Geikins Date: Thu, 21 Aug 2025 12:20:22 +0300 Subject: [PATCH 2/2] fix(fe2): embed token w/ reset auth state breaking SSR (#5286) * fix(fe2): embed token w/ reset auth state breaking SSR * attempt to fix nuxt unavailable --- .../frontend-2/lib/auth/composables/auth.ts | 11 +++++++++-- .../lib/projects/composables/previewImage.ts | 19 ++++++++----------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/packages/frontend-2/lib/auth/composables/auth.ts b/packages/frontend-2/lib/auth/composables/auth.ts index bd8e020dc..e3418ac75 100644 --- a/packages/frontend-2/lib/auth/composables/auth.ts +++ b/packages/frontend-2/lib/auth/composables/auth.ts @@ -140,6 +140,7 @@ const useResetAuthState = ( const resolveDistinctId = useResolveUserDistinctId() const { cbs } = useOnAuthStateChangeState() const authToken = useAuthCookie() + const logger = useLogger() return async ( resetOptions?: Partial<{ @@ -171,7 +172,13 @@ const useResetAuthState = ( // evict entire cache (not enough to just evict user, various other fields // also depend on active user (e.g. Workspace.seatType)) - resetPromise = client.resetStore().then(async () => { + resetPromise = (async () => { + if (import.meta.server) { + logger?.error('attempting to resetStore from SSR') + } else { + await client.resetStore() + } + // wait till active user is reloaded const { data: activeUserRes } = await client .query({ @@ -180,7 +187,7 @@ const useResetAuthState = ( }) .catch(convertThrowIntoFetchResult) user = activeUserRes?.activeUser - }) + })() } resetPromise = resetPromise.then(() => { diff --git a/packages/frontend-2/lib/projects/composables/previewImage.ts b/packages/frontend-2/lib/projects/composables/previewImage.ts index f033e2da2..f5cc40d0b 100644 --- a/packages/frontend-2/lib/projects/composables/previewImage.ts +++ b/packages/frontend-2/lib/projects/composables/previewImage.ts @@ -272,19 +272,16 @@ export function usePreviewImageBlob( } ) } else { + useHead({ + link: computed(() => [ + ...(url.value?.length && isPreviewServiceUrl.value + ? [{ rel: 'preload', as: 'image', href: url.value }] + : []) + ]) + }) + onServerPrefetch(async () => { await regeneratePreviews() - - // Preload the image - if (isPreviewServiceUrl && url.value?.length) { - useHead({ - link: [ - ...(url.value?.length - ? [{ rel: 'preload', as: 'image', href: url.value }] - : []) - ] - }) - } }) }