|
| 1 | +import { Field, Int, ObjectType, Query, Resolver } from 'type-graphql' |
| 2 | + |
| 3 | +import { getSquidDbPool } from '../../test-render/db' |
| 4 | + |
| 5 | +// Schemas match the `stateSchema` values in src/main.ts, src/main-base.ts, |
| 6 | +// src/main-sonic.ts, src/main-hyperliquid.ts. Chain IDs match the `chainId` |
| 7 | +// passed to `run()` in those files. |
| 8 | +const PROCESSORS: Array<{ schema: string; chainId: number }> = [ |
| 9 | + { schema: 'mainnet', chainId: 1 }, |
| 10 | + { schema: 'base', chainId: 8453 }, |
| 11 | + { schema: 'sonic', chainId: 146 }, |
| 12 | + { schema: 'hyperliquid', chainId: 999 }, |
| 13 | +] |
| 14 | + |
| 15 | +@ObjectType() |
| 16 | +class ProcessorStatus { |
| 17 | + @Field() |
| 18 | + schema!: string |
| 19 | + |
| 20 | + @Field(() => Int) |
| 21 | + chainId!: number |
| 22 | + |
| 23 | + // Latest indexed head (max of finalized status.height and hot_block.height). |
| 24 | + // -1 indicates no blocks have been processed yet. |
| 25 | + @Field(() => Int) |
| 26 | + height!: number |
| 27 | + |
| 28 | + // Finalized head from `${schema}.status.height`. |
| 29 | + @Field(() => Int) |
| 30 | + finalizedHeight!: number |
| 31 | + |
| 32 | + // True if both the status table and any expected hot_block rows are present. |
| 33 | + @Field() |
| 34 | + ready!: boolean |
| 35 | + |
| 36 | + @Field({ nullable: true }) |
| 37 | + error?: string |
| 38 | +} |
| 39 | + |
| 40 | +@Resolver() |
| 41 | +export class ProcessorStatusResolver { |
| 42 | + @Query(() => [ProcessorStatus]) |
| 43 | + async processorStatus(): Promise<ProcessorStatus[]> { |
| 44 | + const pool = getSquidDbPool() |
| 45 | + return Promise.all( |
| 46 | + PROCESSORS.map(async ({ schema, chainId }) => { |
| 47 | + try { |
| 48 | + const statusResult = await pool.query<{ height: number }>( |
| 49 | + `SELECT height FROM "${schema}"."status" WHERE id = 0`, |
| 50 | + ) |
| 51 | + if (statusResult.rowCount === 0) { |
| 52 | + return { |
| 53 | + schema, |
| 54 | + chainId, |
| 55 | + height: -1, |
| 56 | + finalizedHeight: -1, |
| 57 | + ready: false, |
| 58 | + error: 'status row missing', |
| 59 | + } |
| 60 | + } |
| 61 | + const finalizedHeight = Number(statusResult.rows[0].height) |
| 62 | + const hotResult = await pool.query<{ height: number | null }>( |
| 63 | + `SELECT MAX(height) AS height FROM "${schema}"."hot_block"`, |
| 64 | + ) |
| 65 | + const hotHeight = |
| 66 | + hotResult.rows[0]?.height != null |
| 67 | + ? Number(hotResult.rows[0].height) |
| 68 | + : -1 |
| 69 | + const height = Math.max(finalizedHeight, hotHeight) |
| 70 | + return { |
| 71 | + schema, |
| 72 | + chainId, |
| 73 | + height, |
| 74 | + finalizedHeight, |
| 75 | + ready: true, |
| 76 | + } |
| 77 | + } catch (err) { |
| 78 | + return { |
| 79 | + schema, |
| 80 | + chainId, |
| 81 | + height: -1, |
| 82 | + finalizedHeight: -1, |
| 83 | + ready: false, |
| 84 | + error: err instanceof Error ? err.message : 'unknown error', |
| 85 | + } |
| 86 | + } |
| 87 | + }), |
| 88 | + ) |
| 89 | + } |
| 90 | +} |
0 commit comments