From 4a78efd07eba06ec0107e75ef9799e59d12e5640 Mon Sep 17 00:00:00 2001 From: Maximilian Kaske Date: Thu, 15 Oct 2026 16:25:14 +0200 Subject: [PATCH] fix(tinybird): keep 47 days in the 15m status MVs and reject offset zone IDs - the endpoints return 45 local days plus today, which spans just under 46d + 1h after a DST fall-back; a 46-day TTL could cut the oldest day, so retain 47 and correct the bound comment (the old "45d + 14h" ignored the elapsed part of today) - `Intl.DateTimeFormat` accepts `+05:30`-style offsets that ClickHouse does not know; refuse them before the request --- .../tinybird/datasources/mv__dns_status_15m__v0.datasource | 2 +- .../tinybird/datasources/mv__grpc_status_15m__v0.datasource | 2 +- .../tinybird/datasources/mv__http_status_15m__v0.datasource | 2 +- .../tinybird/datasources/mv__icmp_status_15m__v0.datasource | 2 +- .../tinybird/datasources/mv__tcp_status_15m__v0.datasource | 2 +- packages/tinybird/endpoints/endpoint__dns_status_15m__v0.pipe | 3 ++- packages/tinybird/endpoints/endpoint__grpc_status_15m__v0.pipe | 3 ++- packages/tinybird/endpoints/endpoint__http_status_15m__v0.pipe | 3 ++- packages/tinybird/endpoints/endpoint__icmp_status_15m__v0.pipe | 3 ++- packages/tinybird/endpoints/endpoint__tcp_status_15m__v0.pipe | 3 ++- packages/tinybird/src/client.test.ts | 2 +- packages/tinybird/src/client.ts | 2 ++ 12 files changed, 18 insertions(+), 11 deletions(-) diff --git a/packages/tinybird/datasources/mv__dns_status_15m__v0.datasource b/packages/tinybird/datasources/mv__dns_status_15m__v0.datasource index bf020ffb8..0a7593f31 100644 --- a/packages/tinybird/datasources/mv__dns_status_15m__v0.datasource +++ b/packages/tinybird/datasources/mv__dns_status_15m__v0.datasource @@ -11,4 +11,4 @@ SCHEMA > ENGINE "AggregatingMergeTree" ENGINE_PARTITION_KEY "toYYYYMM(time)" ENGINE_SORTING_KEY "monitorId, time" -ENGINE_TTL "time + toIntervalDay(46)" +ENGINE_TTL "time + toIntervalDay(47)" diff --git a/packages/tinybird/datasources/mv__grpc_status_15m__v0.datasource b/packages/tinybird/datasources/mv__grpc_status_15m__v0.datasource index 5b20b8b93..138327c35 100644 --- a/packages/tinybird/datasources/mv__grpc_status_15m__v0.datasource +++ b/packages/tinybird/datasources/mv__grpc_status_15m__v0.datasource @@ -11,4 +11,4 @@ SCHEMA > ENGINE "AggregatingMergeTree" ENGINE_PARTITION_KEY "toYYYYMM(time)" ENGINE_SORTING_KEY "monitorId, time" -ENGINE_TTL "time + toIntervalDay(46)" +ENGINE_TTL "time + toIntervalDay(47)" diff --git a/packages/tinybird/datasources/mv__http_status_15m__v0.datasource b/packages/tinybird/datasources/mv__http_status_15m__v0.datasource index b9c5643f9..8a0d33369 100644 --- a/packages/tinybird/datasources/mv__http_status_15m__v0.datasource +++ b/packages/tinybird/datasources/mv__http_status_15m__v0.datasource @@ -11,4 +11,4 @@ SCHEMA > ENGINE "AggregatingMergeTree" ENGINE_PARTITION_KEY "toYYYYMM(time)" ENGINE_SORTING_KEY "monitorId, time" -ENGINE_TTL "time + toIntervalDay(46)" +ENGINE_TTL "time + toIntervalDay(47)" diff --git a/packages/tinybird/datasources/mv__icmp_status_15m__v0.datasource b/packages/tinybird/datasources/mv__icmp_status_15m__v0.datasource index 685e2743b..fe396789c 100644 --- a/packages/tinybird/datasources/mv__icmp_status_15m__v0.datasource +++ b/packages/tinybird/datasources/mv__icmp_status_15m__v0.datasource @@ -11,4 +11,4 @@ SCHEMA > ENGINE "AggregatingMergeTree" ENGINE_PARTITION_KEY "toYYYYMM(time)" ENGINE_SORTING_KEY "monitorId, time" -ENGINE_TTL "time + toIntervalDay(46)" +ENGINE_TTL "time + toIntervalDay(47)" diff --git a/packages/tinybird/datasources/mv__tcp_status_15m__v0.datasource b/packages/tinybird/datasources/mv__tcp_status_15m__v0.datasource index 76e73bd95..40e4e0abc 100644 --- a/packages/tinybird/datasources/mv__tcp_status_15m__v0.datasource +++ b/packages/tinybird/datasources/mv__tcp_status_15m__v0.datasource @@ -11,4 +11,4 @@ SCHEMA > ENGINE "AggregatingMergeTree" ENGINE_PARTITION_KEY "toYYYYMM(time)" ENGINE_SORTING_KEY "monitorId, time" -ENGINE_TTL "time + toIntervalDay(46)" +ENGINE_TTL "time + toIntervalDay(47)" diff --git a/packages/tinybird/endpoints/endpoint__dns_status_15m__v0.pipe b/packages/tinybird/endpoints/endpoint__dns_status_15m__v0.pipe index ce72f612b..ef493021d 100644 --- a/packages/tinybird/endpoints/endpoint__dns_status_15m__v0.pipe +++ b/packages/tinybird/endpoints/endpoint__dns_status_15m__v0.pipe @@ -14,7 +14,8 @@ SELECT FROM mv__dns_status_15m__v0 WHERE monitorId IN {{ Array(monitorIds, 'String', '1,666') }} -- start at a local midnight so the oldest day is complete, not cut at the - -- 46-day TTL edge; stays inside the TTL for every zone (at most 45d + 14h) + -- TTL edge; the bound is under 46d + 1h for every zone (45 local days, one + -- of them 25h after a DST fall-back, plus today so far) and the TTL is 47d AND time >= toStartOfDay(toTimeZone(now(), tz)) - INTERVAL 45 DAY GROUP BY day, monitorId ORDER BY day DESC diff --git a/packages/tinybird/endpoints/endpoint__grpc_status_15m__v0.pipe b/packages/tinybird/endpoints/endpoint__grpc_status_15m__v0.pipe index cb821e87c..41aa7d4c7 100644 --- a/packages/tinybird/endpoints/endpoint__grpc_status_15m__v0.pipe +++ b/packages/tinybird/endpoints/endpoint__grpc_status_15m__v0.pipe @@ -14,7 +14,8 @@ SELECT FROM mv__grpc_status_15m__v0 WHERE monitorId IN {{ Array(monitorIds, 'String', '1,666') }} -- start at a local midnight so the oldest day is complete, not cut at the - -- 46-day TTL edge; stays inside the TTL for every zone (at most 45d + 14h) + -- TTL edge; the bound is under 46d + 1h for every zone (45 local days, one + -- of them 25h after a DST fall-back, plus today so far) and the TTL is 47d AND time >= toStartOfDay(toTimeZone(now(), tz)) - INTERVAL 45 DAY GROUP BY day, monitorId ORDER BY day DESC diff --git a/packages/tinybird/endpoints/endpoint__http_status_15m__v0.pipe b/packages/tinybird/endpoints/endpoint__http_status_15m__v0.pipe index 54fc7e8b2..5f25e5a00 100644 --- a/packages/tinybird/endpoints/endpoint__http_status_15m__v0.pipe +++ b/packages/tinybird/endpoints/endpoint__http_status_15m__v0.pipe @@ -14,7 +14,8 @@ SELECT FROM mv__http_status_15m__v0 WHERE monitorId IN {{ Array(monitorIds, 'String', '1,666') }} -- start at a local midnight so the oldest day is complete, not cut at the - -- 46-day TTL edge; stays inside the TTL for every zone (at most 45d + 14h) + -- TTL edge; the bound is under 46d + 1h for every zone (45 local days, one + -- of them 25h after a DST fall-back, plus today so far) and the TTL is 47d AND time >= toStartOfDay(toTimeZone(now(), tz)) - INTERVAL 45 DAY GROUP BY day, monitorId ORDER BY day DESC diff --git a/packages/tinybird/endpoints/endpoint__icmp_status_15m__v0.pipe b/packages/tinybird/endpoints/endpoint__icmp_status_15m__v0.pipe index 99d5eb70d..1964364aa 100644 --- a/packages/tinybird/endpoints/endpoint__icmp_status_15m__v0.pipe +++ b/packages/tinybird/endpoints/endpoint__icmp_status_15m__v0.pipe @@ -14,7 +14,8 @@ SELECT FROM mv__icmp_status_15m__v0 WHERE monitorId IN {{ Array(monitorIds, 'String', '1,666') }} -- start at a local midnight so the oldest day is complete, not cut at the - -- 46-day TTL edge; stays inside the TTL for every zone (at most 45d + 14h) + -- TTL edge; the bound is under 46d + 1h for every zone (45 local days, one + -- of them 25h after a DST fall-back, plus today so far) and the TTL is 47d AND time >= toStartOfDay(toTimeZone(now(), tz)) - INTERVAL 45 DAY GROUP BY day, monitorId ORDER BY day DESC diff --git a/packages/tinybird/endpoints/endpoint__tcp_status_15m__v0.pipe b/packages/tinybird/endpoints/endpoint__tcp_status_15m__v0.pipe index ae4cbddbd..b63225dee 100644 --- a/packages/tinybird/endpoints/endpoint__tcp_status_15m__v0.pipe +++ b/packages/tinybird/endpoints/endpoint__tcp_status_15m__v0.pipe @@ -14,7 +14,8 @@ SELECT FROM mv__tcp_status_15m__v0 WHERE monitorId IN {{ Array(monitorIds, 'String', '1,666') }} -- start at a local midnight so the oldest day is complete, not cut at the - -- 46-day TTL edge; stays inside the TTL for every zone (at most 45d + 14h) + -- TTL edge; the bound is under 46d + 1h for every zone (45 local days, one + -- of them 25h after a DST fall-back, plus today so far) and the TTL is 47d AND time >= toStartOfDay(toTimeZone(now(), tz)) - INTERVAL 45 DAY GROUP BY day, monitorId ORDER BY day DESC diff --git a/packages/tinybird/src/client.test.ts b/packages/tinybird/src/client.test.ts index cf40311ec..b8e06cc9b 100644 --- a/packages/tinybird/src/client.test.ts +++ b/packages/tinybird/src/client.test.ts @@ -194,7 +194,7 @@ describe("status15mParameters", () => { }); test("rejects zone names ClickHouse would 400 on, before the request", () => { - for (const timezone of ["Mars/Olympus", "", "GMT+1"]) { + for (const timezone of ["Mars/Olympus", "", "GMT+1", "+05:30", "-03:00"]) { const result = status15mParameters.safeParse({ monitorIds: ["1"], timezone, diff --git a/packages/tinybird/src/client.ts b/packages/tinybird/src/client.ts index cbcbf18bd..565acea63 100644 --- a/packages/tinybird/src/client.ts +++ b/packages/tinybird/src/client.ts @@ -18,6 +18,8 @@ const REVALIDATE = env.NODE_ENV === "development" ? DEV_CACHE : 0; const timeZoneValidity = new Map(); export function isValidTimeZone(timeZone: string): boolean { + // Intl also takes `+05:30`-style offsets; ClickHouse only knows zone names. + if (/^[+-]/.test(timeZone)) return false; let valid = timeZoneValidity.get(timeZone); if (valid === undefined) { try { -- 2.54.0