Omit current chart bucket

This commit is contained in:
Ben
2026-06-07 21:37:23 -04:00
parent 2d6b01691c
commit 4f51a4d05c
2 changed files with 39 additions and 32 deletions
@@ -66,34 +66,7 @@ export class ClientStatisticsService {
WITH bounds AS (
SELECT
NOW() - INTERVAL '${windowSql}' AS since,
time_bucket(INTERVAL '10 minutes', NOW()) AS realtime_start
),
aggregate_rows AS (
SELECT
"bucket",
SUM("shares") AS "shares",
SUM("acceptedCount") AS "acceptedCount"
FROM "accepted_share_10m", bounds
WHERE "bucket" > bounds.since
AND "bucket" < bounds.realtime_start
${filterSql}
GROUP BY "bucket"
),
realtime_rows AS (
SELECT
time_bucket(INTERVAL '10 minutes', "acceptedAt") AS "bucket",
SUM("creditedDifficulty") AS "shares",
COUNT(*) AS "acceptedCount"
FROM "accepted_share_entity", bounds
WHERE "acceptedAt" > bounds.since
AND "acceptedAt" >= bounds.realtime_start
${filterSql}
GROUP BY "bucket"
),
combined_rows AS (
SELECT * FROM aggregate_rows
UNION ALL
SELECT * FROM realtime_rows
time_bucket(INTERVAL '10 minutes', NOW()) AS current_bucket
)
SELECT
"label",
@@ -106,7 +79,10 @@ export class ClientStatisticsService {
ROUND((SUM("shares") * ${HASHES_PER_DIFFICULTY}) / ${CHART_BUCKET_SECONDS}) AS "data",
SUM("shares") AS "shares",
SUM("acceptedCount") AS "acceptedCount"
FROM combined_rows
FROM "accepted_share_10m", bounds
WHERE "bucket" > bounds.since
AND "bucket" < bounds.current_bucket
${filterSql}
GROUP BY "bucket"
ORDER BY "bucket" DESC
LIMIT ${limit}
+34 -3
View File
@@ -229,7 +229,7 @@ describe('TimescaleDB and Redis integration', () => {
}]));
});
it('should serve realtime chart and hashrate data from accepted shares', async () => {
it('should serve completed chart buckets and omit the current in-progress bucket', async () => {
const client = await dataSource.getRepository(ClientEntity).save({
address: 'tb1qumezefzdeqqwn5zfvgdrhxjzc5ylr39uhuxcz4',
clientName: 'worker',
@@ -241,7 +241,10 @@ describe('TimescaleDB and Redis integration', () => {
});
const accountingService = new ShareAccountingService(dataSource.getRepository(AcceptedShareEntity));
const statisticsService = new ClientStatisticsService(dataSource);
const acceptedAt = new Date();
const currentBucketStart = Math.floor(Date.now() / (10 * 60 * 1000)) * 10 * 60 * 1000;
const completedBucketStart = currentBucketStart - (10 * 60 * 1000);
const completedBucketEnd = currentBucketStart;
const acceptedAt = new Date(completedBucketStart + 1000);
for (const [index, difficulty] of [64, 32].entries()) {
await accountingService.recordAcceptedShare({
@@ -265,11 +268,36 @@ describe('TimescaleDB and Redis integration', () => {
blockSubmissionResult: null,
});
}
await accountingService.recordAcceptedShare({
protocol: 'sv1',
acceptedAt: new Date(currentBucketStart + 1000),
address: client.address,
clientName: client.clientName,
sessionId: client.sessionId,
clientId: client.id,
jobId: 'current-bucket',
jobTemplateId: 'realtime-template',
blockHeight: 900001,
creditedDifficulty: 1024,
submissionDifficulty: 2048,
networkDifficulty: 100000,
nonce: 'nonce-current',
ntime: '64b3f3ec',
version: '20000000',
extraNonce2: 'c708000000000000',
isBlockCandidate: false,
blockSubmissionResult: null,
});
await dataSource.query(
`CALL refresh_continuous_aggregate('accepted_share_10m', $1::timestamptz, $2::timestamptz)`,
[new Date(completedBucketStart), new Date(completedBucketEnd)],
);
const expectedHashRate = (96 * 4294967296) / 600;
const expectedChartData = Math.round(expectedHashRate).toString();
const expectedLiveHashRate = ((96 + 1024) * 4294967296) / 600;
expect(await statisticsService.getHashRateForGroup(client.address, client.clientName))
.toBeCloseTo(expectedHashRate);
.toBeCloseTo(expectedLiveHashRate);
const addressChart = await statisticsService.getChartDataForAddress(client.address);
const groupChart = await statisticsService.getChartDataForGroup(client.address, client.clientName);
@@ -280,6 +308,9 @@ describe('TimescaleDB and Redis integration', () => {
expect(chart).toEqual(expect.arrayContaining([
expect.objectContaining({ data: expectedChartData }),
]));
expect(chart).not.toEqual(expect.arrayContaining([
expect.objectContaining({ label: new Date(currentBucketStart).toISOString() }),
]));
}
});