diff --git a/indexer/packages/postgres/__tests__/stores/pnl-ticks-table.test.ts b/indexer/packages/postgres/__tests__/stores/pnl-ticks-table.test.ts index 3fb2b036d7..07dfb6b6e7 100644 --- a/indexer/packages/postgres/__tests__/stores/pnl-ticks-table.test.ts +++ b/indexer/packages/postgres/__tests__/stores/pnl-ticks-table.test.ts @@ -184,14 +184,27 @@ describe('PnlTicks store', () => { }), ]); - const latestBlocktime: string = await PnlTicksTable.findLatestProcessedBlocktime(); + const { + maxBlockTime, count, + }: { + maxBlockTime: string, + count: number + } = await PnlTicksTable.findLatestProcessedBlocktimeAndCount(); - expect(latestBlocktime).toEqual(blockTime); + expect(maxBlockTime).toEqual(blockTime); + expect(count).toEqual(2); }); it('Successfully finds latest block time without any pnl ticks', async () => { - const latestBlocktime: string = await PnlTicksTable.findLatestProcessedBlocktime(); - expect(latestBlocktime).toEqual(ZERO_TIME_ISO_8601); + const { + maxBlockTime, count, + }: { + maxBlockTime: string, + count: number + } = await PnlTicksTable.findLatestProcessedBlocktimeAndCount(); + + expect(maxBlockTime).toEqual(ZERO_TIME_ISO_8601); + expect(count).toEqual(0); }); it('createMany PnlTicks, find most recent pnl ticks for each account', async () => { diff --git a/indexer/packages/postgres/src/stores/pnl-ticks-table.ts b/indexer/packages/postgres/src/stores/pnl-ticks-table.ts index 694f4ec861..7024a4c08d 100644 --- a/indexer/packages/postgres/src/stores/pnl-ticks-table.ts +++ b/indexer/packages/postgres/src/stores/pnl-ticks-table.ts @@ -212,17 +212,24 @@ function convertPnlTicksFromDatabaseToPnlTicksCreateObject( return _.omit(pnlTicksFromDatabase, PnlTicksColumns.id); } -export async function findLatestProcessedBlocktime(): Promise { +export async function findLatestProcessedBlocktimeAndCount(): Promise<{ + maxBlockTime: string, + count: number, +}> { const result: { - rows: [{ max: string }] + rows: [{ max: string, count: number }] } = await knexReadReplica.getConnection().raw( ` - SELECT MAX("blockTime") + SELECT MAX("blockTime") as max, COUNT(*) as count FROM "pnl_ticks" ` , - ) as unknown as { rows: [{ max: string }] }; - return result.rows[0].max || ZERO_TIME_ISO_8601; + ) as unknown as { rows: [{ max: string, count: number }] }; + + return { + maxBlockTime: result.rows[0].max || ZERO_TIME_ISO_8601, + count: Number(result.rows[0].count) || 0, + }; } export async function findMostRecentPnlTickForEachAccount( diff --git a/indexer/services/roundtable/__tests__/tasks/create-pnl-ticks.test.ts b/indexer/services/roundtable/__tests__/tasks/create-pnl-ticks.test.ts index 08a77b425f..bcfc6cc11e 100644 --- a/indexer/services/roundtable/__tests__/tasks/create-pnl-ticks.test.ts +++ b/indexer/services/roundtable/__tests__/tasks/create-pnl-ticks.test.ts @@ -277,9 +277,16 @@ describe('create-pnl-ticks', () => { ...testConstants.defaultPnlTick, blockTime: testConstants.defaultBlock.time, }); - const blockTimeIsoString: string = await PnlTicksTable.findLatestProcessedBlocktime(); + const { + maxBlockTime, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + count, + }: { + maxBlockTime: string, + count: number, + } = await PnlTicksTable.findLatestProcessedBlocktimeAndCount(); - const date: number = Date.parse(blockTimeIsoString).valueOf(); + const date: number = Date.parse(maxBlockTime).valueOf(); jest.spyOn(Date, 'now').mockImplementation(() => date); jest.spyOn(DateTime, 'utc').mockImplementation(() => dateTime); jest.spyOn(logger, 'info'); @@ -305,8 +312,48 @@ describe('create-pnl-ticks', () => { expect(pnlTicks.length).toEqual(1); expect(logger.info).toHaveBeenCalledWith( expect.objectContaining({ - message: 'Skipping run because update interval has not been reached', + message: 'Skipping run because update interval has not been reached and all subaccounts have been processed', }), ); }); + + it( + 'calculates pnl per subaccount if last run hit subaccount limit', + async () => { + const pnlTicksHelper = require('../../src/helpers/pnl-ticks-helper'); + const getPnlTicksCreateObjectsSpy = jest.spyOn(pnlTicksHelper, 'getPnlTicksCreateObjects'); + config.PNL_TICK_UPDATE_INTERVAL_MS = 3_600_000; + config.PNL_TICK_MAX_ACCOUNTS_PER_RUN = 1; + await PnlTicksTable.create({ + ...testConstants.defaultPnlTick, + blockTime: testConstants.defaultBlock.time, + }); + const { + maxBlockTime, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + count, + }: { + maxBlockTime: string, + count: number, + } = await PnlTicksTable.findLatestProcessedBlocktimeAndCount(); + + const date: number = Date.parse(maxBlockTime).valueOf(); + jest.spyOn(Date, 'now').mockImplementation(() => date); + jest.spyOn(DateTime, 'utc').mockImplementation(() => dateTime); + jest.spyOn(logger, 'info'); + await LatestAccountPnlTicksCache.set( + pnlTickForSubaccounts, + redisClient, + ); + await Promise.all([ + PerpetualPositionTable.create(testConstants.defaultPerpetualPosition), + PerpetualPositionTable.create({ + ...testConstants.defaultPerpetualPosition, + perpetualId: testConstants.defaultPerpetualMarket2.id, + openEventId: testConstants.defaultTendermintEventId2, + }), + ]); + await createPnlTicksTask(); + expect(getPnlTicksCreateObjectsSpy).toHaveBeenCalledTimes(1); + }); }); diff --git a/indexer/services/roundtable/src/tasks/create-pnl-ticks.ts b/indexer/services/roundtable/src/tasks/create-pnl-ticks.ts index 255afa5a1f..36d7f40698 100644 --- a/indexer/services/roundtable/src/tasks/create-pnl-ticks.ts +++ b/indexer/services/roundtable/src/tasks/create-pnl-ticks.ts @@ -18,26 +18,32 @@ export default async function runTask(): Promise { const startGetNewTicks: number = Date.now(); const [ block, - pnlTickLatestBlocktime, + { + maxBlockTime, + count, + }, ]: [ BlockFromDatabase, - string, + { + maxBlockTime: string, + count: number, + }, ] = await Promise.all([ BlockTable.getLatest({ readReplica: true }), - PnlTicksTable.findLatestProcessedBlocktime(), + PnlTicksTable.findLatestProcessedBlocktimeAndCount(), ]); const latestBlockTime: string = block.time; const latestBlockHeight: string = block.blockHeight; // Check that the latest block time is within PNL_TICK_UPDATE_INTERVAL_MS of the last computed // PNL tick block time. if ( - Date.parse(latestBlockTime) - normalizeStartTime(new Date(pnlTickLatestBlocktime)).getTime() < - config.PNL_TICK_UPDATE_INTERVAL_MS + Date.parse(latestBlockTime) - normalizeStartTime(new Date(maxBlockTime)).getTime() < + config.PNL_TICK_UPDATE_INTERVAL_MS && count < config.PNL_TICK_MAX_ACCOUNTS_PER_RUN ) { logger.info({ at: 'create-pnl-ticks#runTask', - message: 'Skipping run because update interval has not been reached', - pnlTickLatestBlocktime, + message: 'Skipping run because update interval has not been reached and all subaccounts have been processed', + pnlTickLatestBlocktime: maxBlockTime, latestBlockTime, threshold: config.PNL_TICK_UPDATE_INTERVAL_MS, });