From 14d412076542851aaa8700b947f41969762d38a6 Mon Sep 17 00:00:00 2001 From: Shine Li Date: Tue, 21 May 2024 17:38:57 +1000 Subject: [PATCH] feat: add config for minting backend (#1810) --- packages/minting-backend/sdk/package.json | 4 +- .../sdk/src/analytics/index.ts | 43 ++ .../minting-backend/sdk/src/config/index.ts | 34 ++ packages/minting-backend/sdk/src/index.ts | 66 +++- packages/minting-backend/sdk/src/minting.ts | 4 + .../sdk/src/persistence/pg/postgres.ts | 182 ++++----- .../src/persistence/prismaSqlite/sqlite.ts | 370 +++++++++--------- yarn.lock | 2 + 8 files changed, 431 insertions(+), 274 deletions(-) create mode 100644 packages/minting-backend/sdk/src/analytics/index.ts create mode 100644 packages/minting-backend/sdk/src/config/index.ts diff --git a/packages/minting-backend/sdk/package.json b/packages/minting-backend/sdk/package.json index e34953687e..6fd9633376 100644 --- a/packages/minting-backend/sdk/package.json +++ b/packages/minting-backend/sdk/package.json @@ -6,7 +6,9 @@ "bugs": "https://github.com/immutable/ts-immutable-sdk/issues", "dependencies": { "@imtbl/blockchain-data": "0.0.0", - "@imtbl/config": "0.0.0" + "@imtbl/config": "0.0.0", + "@imtbl/metrics": "0.0.0", + "@imtbl/webhook": "0.0.0" }, "devDependencies": { "@rollup/plugin-typescript": "^11.0.0", diff --git a/packages/minting-backend/sdk/src/analytics/index.ts b/packages/minting-backend/sdk/src/analytics/index.ts new file mode 100644 index 0000000000..4fc249bdee --- /dev/null +++ b/packages/minting-backend/sdk/src/analytics/index.ts @@ -0,0 +1,43 @@ +import { track } from '@imtbl/metrics'; + +const moduleName = 'minting_backend_sdk'; + +export const trackInitializePersistencePG = () => { + try { + track(moduleName, 'initializePersistencePG'); + } catch { + // ignore + } +}; + +export const trackInitializePersistencePrismaSqlite = () => { + try { + track(moduleName, 'initializePersistencePrismaSqlite'); + } catch { + // ignore + } +}; + +export const trackSubmitMintingRequests = () => { + try { + track(moduleName, 'submitMintingRequests'); + } catch { + // ignore + } +}; + +export const trackProcessMint = () => { + try { + track(moduleName, 'processMint'); + } catch { + // ignore + } +}; + +export const trackRecordMint = () => { + try { + track(moduleName, 'recordMint'); + } catch { + // ignore + } +}; diff --git a/packages/minting-backend/sdk/src/config/index.ts b/packages/minting-backend/sdk/src/config/index.ts new file mode 100644 index 0000000000..f462cc4e19 --- /dev/null +++ b/packages/minting-backend/sdk/src/config/index.ts @@ -0,0 +1,34 @@ +/* eslint-disable implicit-arrow-linebreak */ +import { + ImmutableConfiguration, + ModuleConfiguration +} from '@imtbl/config'; + +import { + BlockchainData, + BlockchainDataModuleConfiguration +} from '@imtbl/blockchain-data'; + +import { MintingPersistence } from '../persistence/type'; + +export interface MintingBackendModuleParams { } + +export interface MintingBackendModuleConfiguration + extends ModuleConfiguration { + persistence: MintingPersistence; + blockchainDataModuleConfiguration: BlockchainDataModuleConfiguration; +} + +export class MintingBackendConfiguration { + readonly baseConfig: ImmutableConfiguration; + + readonly blockChainDataClient: BlockchainData; + + readonly persistence: MintingPersistence; + + constructor({ baseConfig, blockchainDataModuleConfiguration, persistence }: MintingBackendModuleConfiguration) { + this.baseConfig = baseConfig; + this.blockChainDataClient = new BlockchainData(blockchainDataModuleConfiguration); + this.persistence = persistence; + } +} diff --git a/packages/minting-backend/sdk/src/index.ts b/packages/minting-backend/sdk/src/index.ts index 4a539030c9..4f5a65ee43 100644 --- a/packages/minting-backend/sdk/src/index.ts +++ b/packages/minting-backend/sdk/src/index.ts @@ -1,11 +1,75 @@ +import { ImmutableConfiguration, ModuleConfiguration } from '@imtbl/config'; +import { BlockchainData } from '@imtbl/blockchain-data'; +import { init } from '@imtbl/webhook'; import { mintingPersistence as mintingPersistencePg } from './persistence/pg/postgres'; import { mintingPersistence as mintingPersistencePrismaSqlite } from './persistence/prismaSqlite/sqlite'; import { - submitMintingRequests, processMint, recordMint + submitMintingRequests, processMint, recordMint, + MintRequestEvent } from './minting'; +import { CreateMintRequest, MintingPersistence } from './persistence/type'; +import { Logger } from './logger/type'; export { submitMintingRequests, processMint, recordMint, // database clients mintingPersistencePg, mintingPersistencePrismaSqlite }; + +export interface MintingBackendModuleConfiguration + extends ModuleConfiguration { + persistence: MintingPersistence; + logger?: Logger; +} + +const noopHandlers = { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + zkevmMintRequestUpdated: async (event: MintRequestEvent) => { }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + others: async (..._args: any) => { } +}; + +export class MintingBackendModule { + private readonly baseConfig: ImmutableConfiguration; + + private readonly persistence: MintingPersistence; + + private readonly blockchainDataClient: BlockchainData; + + private readonly logger: Logger; + + constructor(config: MintingBackendModuleConfiguration) { + this.baseConfig = config.baseConfig; + this.persistence = config.persistence; + this.logger = config.logger || console; + this.blockchainDataClient = new BlockchainData({ + baseConfig: config.baseConfig + }); + } + + async recordMint(mintRequest: CreateMintRequest) { + await recordMint(this.persistence, mintRequest); + } + + async submitMintingRequests(config: { + defaultBatchSize?: number; + chainName?: string; + maxNumberOfTries?: number; + }) { + await submitMintingRequests( + this.persistence, + this.blockchainDataClient, + config + ); + } + + async processMint(body: string | Record, otherHandlers = noopHandlers) { + await init(body, this.baseConfig.environment, { + zkevmMintRequestUpdated: async (event: MintRequestEvent) => { + await processMint(this.persistence, event, this.logger); + otherHandlers.zkevmMintRequestUpdated(event); + }, + others: otherHandlers.others + }); + } +} diff --git a/packages/minting-backend/sdk/src/minting.ts b/packages/minting-backend/sdk/src/minting.ts index 92df452ced..8d47ae0616 100644 --- a/packages/minting-backend/sdk/src/minting.ts +++ b/packages/minting-backend/sdk/src/minting.ts @@ -5,6 +5,7 @@ import { BlockchainData as Types } from '@imtbl/generated-clients'; import { BlockchainData } from '@imtbl/blockchain-data'; import { CreateMintRequest, MintRequest, MintingPersistence } from './persistence/type'; import { Logger } from './logger/type'; +import { trackProcessMint, trackRecordMint, trackSubmitMintingRequests } from './analytics'; // TODO: expose metrics // - submitting status count, conflicting status count @@ -14,6 +15,7 @@ export const recordMint = async ( mintingPersistence: MintingPersistence, mintRequest: CreateMintRequest ) => { + trackRecordMint(); mintingPersistence.recordMint(mintRequest); }; @@ -32,6 +34,7 @@ export const submitMintingRequests = async ( }, logger: Logger = console ) => { + trackSubmitMintingRequests(); let mintingResponse: Types.CreateMintRequestResult | undefined; // eslint-disable-next-line no-constant-condition while (true) { @@ -214,6 +217,7 @@ export const processMint = async ( event: MintRequestEvent, logger: Logger = console ) => { + trackProcessMint(); if (event.event_name !== 'imtbl_zkevm_mint_request_updated') { logger.info( `${event.event_name} is not imtbl_zkevm_mint_request_updated, skip.` diff --git a/packages/minting-backend/sdk/src/persistence/pg/postgres.ts b/packages/minting-backend/sdk/src/persistence/pg/postgres.ts index ba1ae4e25a..f2553ff4c9 100644 --- a/packages/minting-backend/sdk/src/persistence/pg/postgres.ts +++ b/packages/minting-backend/sdk/src/persistence/pg/postgres.ts @@ -1,94 +1,98 @@ import type { Pool } from 'pg'; import { CreateMintRequest, MintingPersistence, SubmittedMintRequest } from '../type'; +import { trackInitializePersistencePG } from '../../analytics'; -export const mintingPersistence = (client: Pool): MintingPersistence => ({ - recordMint: async (request: CreateMintRequest) => { - const r = await client.query( - ` - INSERT INTO im_assets (asset_id, contract_address, owner_address, metadata) - VALUES ($1, $2, $3, $4) ON CONFLICT (asset_id, contract_address) DO NOTHING; - `, - [request.asset_id, request.contract_address, request.owner_address, request.metadata] - ); - if (r.rowCount === 0) { - throw new Error('Duplicated mint'); - } - }, - getNextBatchForSubmission: async (limit: number) => { - const res = await client.query(` - UPDATE im_assets SET minting_status = 'submitting' WHERE minting_status IS NULL and id in ( - select id from im_assets where minting_status is null limit $1 for update skip locked - ) returning *; - `, [limit]); - return res.rows; - }, - updateMintingStatusToSubmitted: async (ids: string[]) => { - await client.query(` - UPDATE im_assets SET minting_status = $2 WHERE id = ANY($1); - `, [ids, 'submitted']); - }, - syncMintingStatus: async (submittedMintRequest: SubmittedMintRequest) => { - // doing a upsert just in case the row has not been created yet - await client.query(` - INSERT INTO im_assets ( - asset_id, - contract_address, - owner_address, - token_id, - minting_status, - metadata_id, - last_imtbl_zkevm_mint_request_updated_id, - error - ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT (asset_id, contract_address) - DO UPDATE SET - owner_address = $3, - token_id = $4, - minting_status = $5, - metadata_id = $6, - last_imtbl_zkevm_mint_request_updated_id = $7, - error = $8 - where ( - im_assets.last_imtbl_zkevm_mint_request_updated_id < $7 OR - im_assets.last_imtbl_zkevm_mint_request_updated_id is null +export const mintingPersistence = (client: Pool): MintingPersistence => { + trackInitializePersistencePG(); + return { + recordMint: async (request: CreateMintRequest) => { + const r = await client.query( + ` + INSERT INTO im_assets (asset_id, contract_address, owner_address, metadata) + VALUES ($1, $2, $3, $4) ON CONFLICT (asset_id, contract_address) DO NOTHING; + `, + [request.asset_id, request.contract_address, request.owner_address, request.metadata] ); - `, [ - submittedMintRequest.assetId, - submittedMintRequest.contractAddress, - submittedMintRequest.ownerAddress, - submittedMintRequest.tokenId, - submittedMintRequest.status, - submittedMintRequest.metadataId, - submittedMintRequest.imtblZkevmMintRequestUpdatedId, - submittedMintRequest.error]); - }, - markAsConflict: async (assetIds: string[], contractAddress: string) => { - await client.query(` - UPDATE im_assets - SET minting_status = 'conflicting' - WHERE asset_id = ANY($1) - AND contract_address = $2; - `, [assetIds, contractAddress]); - }, - resetMintingStatus: async (ids: string[]) => { - await client.query(` - UPDATE im_assets SET minting_status = null WHERE id = ANY($1); - `, [ids]); - }, - markForRetry: async (ids: string[]) => { - await client.query(` - UPDATE im_assets - SET minting_status = null, tried_count = tried_count + 1 WHERE id = ANY($1); + if (r.rowCount === 0) { + throw new Error('Duplicated mint'); + } + }, + getNextBatchForSubmission: async (limit: number) => { + const res = await client.query(` + UPDATE im_assets SET minting_status = 'submitting' WHERE minting_status IS NULL and id in ( + select id from im_assets where minting_status is null limit $1 for update skip locked + ) returning *; + `, [limit]); + return res.rows; + }, + updateMintingStatusToSubmitted: async (ids: string[]) => { + await client.query(` + UPDATE im_assets SET minting_status = $2 WHERE id = ANY($1); + `, [ids, 'submitted']); + }, + syncMintingStatus: async (submittedMintRequest: SubmittedMintRequest) => { + // doing a upsert just in case the row has not been created yet + await client.query(` + INSERT INTO im_assets ( + asset_id, + contract_address, + owner_address, + token_id, + minting_status, + metadata_id, + last_imtbl_zkevm_mint_request_updated_id, + error + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT (asset_id, contract_address) + DO UPDATE SET + owner_address = $3, + token_id = $4, + minting_status = $5, + metadata_id = $6, + last_imtbl_zkevm_mint_request_updated_id = $7, + error = $8 + where ( + im_assets.last_imtbl_zkevm_mint_request_updated_id < $7 OR + im_assets.last_imtbl_zkevm_mint_request_updated_id is null + ); + `, [ + submittedMintRequest.assetId, + submittedMintRequest.contractAddress, + submittedMintRequest.ownerAddress, + submittedMintRequest.tokenId, + submittedMintRequest.status, + submittedMintRequest.metadataId, + submittedMintRequest.imtblZkevmMintRequestUpdatedId, + submittedMintRequest.error]); + }, + markAsConflict: async (assetIds: string[], contractAddress: string) => { + await client.query(` + UPDATE im_assets + SET minting_status = 'conflicting' + WHERE asset_id = ANY($1) + AND contract_address = $2; + `, [assetIds, contractAddress]); + }, + resetMintingStatus: async (ids: string[]) => { + await client.query(` + UPDATE im_assets SET minting_status = null WHERE id = ANY($1); + `, [ids]); + }, + markForRetry: async (ids: string[]) => { + await client.query(` + UPDATE im_assets + SET minting_status = null, tried_count = tried_count + 1 WHERE id = ANY($1); + `, [ids]); + }, + updateMintingStatusToSubmissionFailed: async (ids: string[]) => { + await client.query(` + UPDATE im_assets SET minting_status = 'submission_failed' WHERE id = ANY($1); `, [ids]); - }, - updateMintingStatusToSubmissionFailed: async (ids: string[]) => { - await client.query(` - UPDATE im_assets SET minting_status = 'submission_failed' WHERE id = ANY($1); - `, [ids]); - }, - getMintingRequest: async (contractAddress: string, referenceId: string) => { - const res = await client.query(` - SELECT * FROM im_assets WHERE contract_address = $1 and asset_id = $2; - `, [contractAddress, referenceId]); - return res.rows[0] || null; - } -}); + }, + getMintingRequest: async (contractAddress: string, referenceId: string) => { + const res = await client.query(` + SELECT * FROM im_assets WHERE contract_address = $1 and asset_id = $2; + `, [contractAddress, referenceId]); + return res.rows[0] || null; + } + }; +}; diff --git a/packages/minting-backend/sdk/src/persistence/prismaSqlite/sqlite.ts b/packages/minting-backend/sdk/src/persistence/prismaSqlite/sqlite.ts index 79bd438770..0ee1ddc378 100644 --- a/packages/minting-backend/sdk/src/persistence/prismaSqlite/sqlite.ts +++ b/packages/minting-backend/sdk/src/persistence/prismaSqlite/sqlite.ts @@ -1,219 +1,223 @@ /* eslint-disable no-await-in-loop */ /* eslint-disable @typescript-eslint/naming-convention */ +import { trackInitializePersistencePrismaSqlite } from '../../analytics'; import { CreateMintRequest, MintingPersistence, SubmittedMintRequest } from '../type'; // client is a PrismaClient instance. it needs to be generated with // additional schema defined inside (TODO: point to repo) file. -export const mintingPersistence = (client: any): MintingPersistence => ({ - recordMint: async (request: CreateMintRequest) => { - const result = await client.imAssets.upsert({ - where: { - im_assets_uindex: { - assetId: request.asset_id, contractAddress: request.contract_address - } - }, - update: {}, // Do nothing on conflict - create: { - assetId: request.asset_id, - contractAddress: request.contract_address, - ownerAddress: request.owner_address, - metadata: JSON.stringify(request.metadata), // Serialize JSON metadata - }, - }); +export const mintingPersistence = (client: any): MintingPersistence => { + trackInitializePersistencePrismaSqlite(); + return { + recordMint: async (request: CreateMintRequest) => { + const result = await client.imAssets.upsert({ + where: { + im_assets_uindex: { + assetId: request.asset_id, contractAddress: request.contract_address + } + }, + update: {}, // Do nothing on conflict + create: { + assetId: request.asset_id, + contractAddress: request.contract_address, + ownerAddress: request.owner_address, + metadata: JSON.stringify(request.metadata), // Serialize JSON metadata + }, + }); - // Since upsert does not throw on update and does not tell directly if it updated or inserted, - // we need to add additional logic to handle this if "result" does not provide enough info. - if (!result) { - throw new Error('Duplicated mint'); - } - }, - // WARNING: this is NOT concurrency safe. Please only call this method one at a time. - getNextBatchForSubmission: async (limit: number) => { - const assets = await client.imAssets.findMany({ - where: { - mintingStatus: null - }, - take: limit - }); + // Since upsert does not throw on update and does not tell directly if it updated or inserted, + // we need to add additional logic to handle this if "result" does not provide enough info. + if (!result) { + throw new Error('Duplicated mint'); + } + }, + // WARNING: this is NOT concurrency safe. Please only call this method one at a time. + getNextBatchForSubmission: async (limit: number) => { + const assets = await client.imAssets.findMany({ + where: { + mintingStatus: null + }, + take: limit + }); - const assetIds = assets.map((asset: { id: string; }) => asset.id); + const assetIds = assets.map((asset: { id: string; }) => asset.id); - await client.imAssets.updateMany({ - where: { - id: { - in: assetIds + await client.imAssets.updateMany({ + where: { + id: { + in: assetIds + } + }, + data: { + mintingStatus: 'submitting' } - }, - data: { - mintingStatus: 'submitting' - } - }); + }); - const updatedAssets = await client.imAssets.findMany({ - where: { - id: { - in: assetIds - } - } - }); - return updatedAssets.map((asset: any) => ({ - id: asset.id, - contract_address: asset.contractAddress, - wallet_address: asset.ownerAddress, - asset_id: asset.assetId, - metadata: asset.metadata ? JSON.parse(asset.metadata) : null, - owner_address: asset.ownerAddress, - tried_count: asset.triedCount, - })); - }, - updateMintingStatusToSubmitted: async (ids: string[]) => { - await client.imAssets.updateMany({ - where: { - id: { - in: ids + const updatedAssets = await client.imAssets.findMany({ + where: { + id: { + in: assetIds + } } - }, - data: { - mintingStatus: 'submitted' - } - }); - }, - syncMintingStatus: async (submittedMintRequest: SubmittedMintRequest) => { - // First, attempt to retrieve the existing asset - const existingAsset = await client.imAssets.findUnique({ - where: { - im_assets_uindex: { - assetId: submittedMintRequest.assetId, - contractAddress: submittedMintRequest.contractAddress, + }); + return updatedAssets.map((asset: any) => ({ + id: asset.id, + contract_address: asset.contractAddress, + wallet_address: asset.ownerAddress, + asset_id: asset.assetId, + metadata: asset.metadata ? JSON.parse(asset.metadata) : null, + owner_address: asset.ownerAddress, + tried_count: asset.triedCount, + })); + }, + updateMintingStatusToSubmitted: async (ids: string[]) => { + await client.imAssets.updateMany({ + where: { + id: { + in: ids + } }, - } - }); - - // Check if the asset exists and the condition for updating is met - if (existingAsset && ( - existingAsset.lastImtblZkevmMintRequestUpdatedId === null - || existingAsset.lastImtblZkevmMintRequestUpdatedId < submittedMintRequest.imtblZkevmMintRequestUpdatedId) - ) { - // Perform update if the existing record's lastImtblZkevmMintRequestUpdatedId is less than the new one or is null - await client.imAssets.update({ + data: { + mintingStatus: 'submitted' + } + }); + }, + syncMintingStatus: async (submittedMintRequest: SubmittedMintRequest) => { + // First, attempt to retrieve the existing asset + const existingAsset = await client.imAssets.findUnique({ where: { im_assets_uindex: { assetId: submittedMintRequest.assetId, contractAddress: submittedMintRequest.contractAddress, }, + } + }); + + // Check if the asset exists and the condition for updating is met + if (existingAsset && ( + existingAsset.lastImtblZkevmMintRequestUpdatedId === null + || existingAsset.lastImtblZkevmMintRequestUpdatedId < submittedMintRequest.imtblZkevmMintRequestUpdatedId) + ) { + // Perform update if the existing record's lastImtblZkevmMintRequestUpdatedId is less than the new one or is null + await client.imAssets.update({ + where: { + im_assets_uindex: { + assetId: submittedMintRequest.assetId, + contractAddress: submittedMintRequest.contractAddress, + }, + }, + data: { + ownerAddress: submittedMintRequest.ownerAddress, + tokenId: submittedMintRequest.tokenId, + mintingStatus: submittedMintRequest.status, + metadataId: submittedMintRequest.metadataId, + lastImtblZkevmMintRequestUpdatedId: submittedMintRequest.imtblZkevmMintRequestUpdatedId, + error: submittedMintRequest.error, + } + }); + } else if (!existingAsset) { + // Perform insert if no existing record is found + await client.imAssets.create({ + data: { + assetId: submittedMintRequest.assetId, + contractAddress: submittedMintRequest.contractAddress, + ownerAddress: submittedMintRequest.ownerAddress, + tokenId: submittedMintRequest.tokenId, + mintingStatus: submittedMintRequest.status, + metadataId: submittedMintRequest.metadataId, + lastImtblZkevmMintRequestUpdatedId: submittedMintRequest.imtblZkevmMintRequestUpdatedId, + error: submittedMintRequest.error, + } + }); + } + // If existing asset does not meet the update condition, do nothing + }, + updateMintingStatusToSubmissionFailed: async (ids: string[]) => { + await client.imAssets.updateMany({ + where: { + id: { + in: ids + } }, data: { - ownerAddress: submittedMintRequest.ownerAddress, - tokenId: submittedMintRequest.tokenId, - mintingStatus: submittedMintRequest.status, - metadataId: submittedMintRequest.metadataId, - lastImtblZkevmMintRequestUpdatedId: submittedMintRequest.imtblZkevmMintRequestUpdatedId, - error: submittedMintRequest.error, + mintingStatus: 'submission_failed' } }); - } else if (!existingAsset) { - // Perform insert if no existing record is found - await client.imAssets.create({ + }, + markAsConflict: async (assetIds: string[], contractAddress: string) => { + await client.imAssets.updateMany({ + where: { + assetId: { + in: assetIds // Targets assets where assetId is in the provided list + }, + contractAddress // Additional condition for contract address + }, data: { - assetId: submittedMintRequest.assetId, - contractAddress: submittedMintRequest.contractAddress, - ownerAddress: submittedMintRequest.ownerAddress, - tokenId: submittedMintRequest.tokenId, - mintingStatus: submittedMintRequest.status, - metadataId: submittedMintRequest.metadataId, - lastImtblZkevmMintRequestUpdatedId: submittedMintRequest.imtblZkevmMintRequestUpdatedId, - error: submittedMintRequest.error, + mintingStatus: 'conflicting' // Set the new status } }); - } - // If existing asset does not meet the update condition, do nothing - }, - updateMintingStatusToSubmissionFailed: async (ids: string[]) => { - await client.imAssets.updateMany({ - where: { - id: { - in: ids - } - }, - data: { - mintingStatus: 'submission_failed' - } - }); - }, - markAsConflict: async (assetIds: string[], contractAddress: string) => { - await client.imAssets.updateMany({ - where: { - assetId: { - in: assetIds // Targets assets where assetId is in the provided list + }, + resetMintingStatus: async (ids: string[]) => { + await client.imAssets.updateMany({ + where: { + id: { + in: ids // Condition to match ids + } }, - contractAddress // Additional condition for contract address - }, - data: { - mintingStatus: 'conflicting' // Set the new status - } - }); - }, - resetMintingStatus: async (ids: string[]) => { - await client.imAssets.updateMany({ - where: { - id: { - in: ids // Condition to match ids + data: { + mintingStatus: null // Setting minting_status to null } - }, - data: { - mintingStatus: null // Setting minting_status to null - } - }); - }, - // this method is not concurrency safe - markForRetry: async (ids: string[]) => { - // Retrieve the current values of tried_count for the specified ids - const assets = await client.imAssets.findMany({ - where: { - id: { - in: ids + }); + }, + // this method is not concurrency safe + markForRetry: async (ids: string[]) => { + // Retrieve the current values of tried_count for the specified ids + const assets = await client.imAssets.findMany({ + where: { + id: { + in: ids + } + }, + select: { + id: true, + triedCount: true // Assuming the field is named triedCount } - }, - select: { - id: true, - triedCount: true // Assuming the field is named triedCount - } - }); + }); - // Update each asset with the new tried_count and nullify minting_status - for (const asset of assets) { - await client.imAssets.update({ + // Update each asset with the new tried_count and nullify minting_status + for (const asset of assets) { + await client.imAssets.update({ + where: { + id: asset.id + }, + data: { + mintingStatus: null, + triedCount: asset.triedCount + 1 + } + }); + } + }, + getMintingRequest: async (contractAddress: string, referenceId: string) => { + // Retrieve the asset from the database based on contract_address and asset_id + const asset = await client.imAssets.findFirst({ where: { - id: asset.id - }, - data: { - mintingStatus: null, - triedCount: asset.triedCount + 1 + contractAddress, + assetId: referenceId } }); - } - }, - getMintingRequest: async (contractAddress: string, referenceId: string) => { - // Retrieve the asset from the database based on contract_address and asset_id - const asset = await client.imAssets.findFirst({ - where: { - contractAddress, - assetId: referenceId + if (!asset) { + return null; } - }); - if (!asset) { - return null; + return { + asset_id: asset.assetId, + contract_address: asset.contractAddress, + id: asset.id, + metadata: asset.metadata ? JSON.parse(asset.metadata) : null, + owner_address: asset.ownerAddress, + tried_count: asset.triedCount, + wallet_address: asset.ownerAddress + }; } - return { - asset_id: asset.assetId, - contract_address: asset.contractAddress, - id: asset.id, - metadata: asset.metadata ? JSON.parse(asset.metadata) : null, - owner_address: asset.ownerAddress, - tried_count: asset.triedCount, - wallet_address: asset.ownerAddress - }; - } -}); + }; +}; diff --git a/yarn.lock b/yarn.lock index 1ea38d98ee..5b0e7edfd0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3699,6 +3699,8 @@ __metadata: dependencies: "@imtbl/blockchain-data": 0.0.0 "@imtbl/config": 0.0.0 + "@imtbl/metrics": 0.0.0 + "@imtbl/webhook": 0.0.0 "@rollup/plugin-typescript": ^11.0.0 "@swc/core": ^1.3.36 "@swc/jest": ^0.2.24