diff --git a/app/api/job/handler/sync-analysis-results.ts b/app/api/job/handler/sync-analysis-results.ts index 3be7639..06e80d5 100644 --- a/app/api/job/handler/sync-analysis-results.ts +++ b/app/api/job/handler/sync-analysis-results.ts @@ -1,5 +1,5 @@ import { createUserAnalysesApi } from '@/packages/features/user-analyses/src/server/api'; -import { getSupabaseServerClient } from '@/packages/supabase/src/clients/server-client'; +import { getSupabaseServerAdminClient } from '@/packages/supabase/src/clients/server-admin-client'; import { readPrivateMessageResponse } from '~/lib/services/medipost/medipostPrivateMessage.service'; @@ -19,7 +19,7 @@ type GroupedResults = { export default async function syncAnalysisResults() { console.info('Syncing analysis results'); - const supabase = getSupabaseServerClient(); + const supabase = getSupabaseServerAdminClient(); const api = createUserAnalysesApi(supabase); const processedMessages: ProcessedMessage[] = []; diff --git a/app/home/(user)/_lib/server/load-tto-services.ts b/app/home/(user)/_lib/server/load-tto-services.ts index 530f959..170b26a 100644 --- a/app/home/(user)/_lib/server/load-tto-services.ts +++ b/app/home/(user)/_lib/server/load-tto-services.ts @@ -7,6 +7,7 @@ import { ServiceCategory } from '../../_components/service-categories'; async function ttoServicesLoader() { const response = await getProductCategories({ fields: '*products, is_active, metadata', + limit: 100, }); const heroCategories = response.product_categories?.filter( diff --git a/lib/services/doctor-jobs.service.ts b/lib/services/doctor-jobs.service.ts index db9a34e..275e803 100644 --- a/lib/services/doctor-jobs.service.ts +++ b/lib/services/doctor-jobs.service.ts @@ -7,7 +7,7 @@ async function getAssignedOrderIds() { .schema('medreport') .from('doctor_analysis_feedback') .select('analysis_order_id') - .not('status', 'is', 'COMPLETED') + .not('status', 'eq', 'COMPLETED') .not('doctor_user_id', 'is', null) .throwOnError(); diff --git a/packages/features/medusa-storefront/src/lib/data/customer.ts b/packages/features/medusa-storefront/src/lib/data/customer.ts index 6f36e75..29d8c39 100644 --- a/packages/features/medusa-storefront/src/lib/data/customer.ts +++ b/packages/features/medusa-storefront/src/lib/data/customer.ts @@ -15,6 +15,12 @@ import { removeCartId, setAuthToken, } from './cookies'; +import { withRetries } from '../util/with-retries'; + +const MedusaApiRetriesDefaultConfig = { + attempts: 3, + baseDelayMs: 1000, +}; export const retrieveCustomer = async (): Promise => { @@ -268,11 +274,21 @@ export const updateCustomerAddress = async ( }; async function medusaLogin(email: string, password: string) { - const token = await sdk.auth.login('customer', 'emailpass', { - email, - password, + const token = await withRetries(async () => { + const loginToken = await sdk.auth.login('customer', 'emailpass', { + email, + password, + }); + if (typeof loginToken !== 'string') { + throw new Error('Failed to login Medusa account'); + } + return loginToken; + }, { + ...MedusaApiRetriesDefaultConfig, + label: 'medusa.auth.login', }); - await setAuthToken(token as string); + + await setAuthToken(token); try { await transferCart(); @@ -303,20 +319,38 @@ async function medusaRegister({ `Creating new Medusa account for Keycloak user with email=${email}`, ); - const registerToken = await sdk.auth.register('customer', 'emailpass', { - email, - password, - }); + const registerToken = await withRetries( + async () => { + const token = await sdk.auth.register('customer', 'emailpass', { + email, + password, + }); + if (typeof token !== 'string') { + throw new Error('Failed to register Medusa account'); + } + return token; + }, + { + ...MedusaApiRetriesDefaultConfig, + label: 'medusa.auth.register', + }, + ); await setAuthToken(registerToken); console.info( `Creating new Medusa customer profile for Keycloak user with email=${email} and name=${name} and lastName=${lastName}`, ); - await sdk.store.customer.create( - { email, first_name: name, last_name: lastName }, - {}, + await withRetries( + async () => { + await sdk.store.customer.create( + { email, first_name: name, last_name: lastName }, + {}, + { ...(await getAuthHeaders()) }, + ); + }, { - ...(await getAuthHeaders()), + ...MedusaApiRetriesDefaultConfig, + label: 'medusa.customer.create', }, ); } diff --git a/packages/features/medusa-storefront/src/lib/util/index.ts b/packages/features/medusa-storefront/src/lib/util/index.ts index 5c5ec86..70232ac 100644 --- a/packages/features/medusa-storefront/src/lib/util/index.ts +++ b/packages/features/medusa-storefront/src/lib/util/index.ts @@ -8,3 +8,4 @@ export * from './money'; export * from './product'; export * from './repeat'; export * from './sort-products'; +export * from './with-retries'; diff --git a/packages/features/medusa-storefront/src/lib/util/with-retries.ts b/packages/features/medusa-storefront/src/lib/util/with-retries.ts new file mode 100644 index 0000000..c73a96f --- /dev/null +++ b/packages/features/medusa-storefront/src/lib/util/with-retries.ts @@ -0,0 +1,45 @@ +type RetryOptions = { + attempts?: number; + baseDelayMs?: number; + label?: string; +}; + +function sleep(delay: number) { + return new Promise((resolve) => setTimeout(resolve, delay)); +} + +export async function withRetries( + operation: () => Promise, + { attempts = 3, baseDelayMs = 500, label }: RetryOptions = {} +): Promise { + let lastError: unknown; + + for (let attempt = 1; attempt <= attempts; attempt++) { + try { + return await operation(); + } catch (error) { + lastError = error; + + if (attempt === attempts) { + break; + } + + const delay = baseDelayMs * 2 ** (attempt - 1); + + if (label) { + console.warn( + `Retrying ${label}, attempt ${attempt + 1}/${attempts} in ${delay}ms`, + error + ); + } + + if (delay > 0) { + await sleep(delay); + } + } + } + + throw lastError instanceof Error + ? lastError + : new Error("Operation failed after retries"); +}