Round the Postgres clock down to the second, like SQLite

This commit is contained in:
binwiederhier committed 2026-10-30 21:23:03 +00:00
1 parent 6674f3b5bd
commit 6a573ab5c1
2 files changed
+30 -3

No files matched your search

+4 -3
View File
@@ -6,15 +6,16 @@ import (
"heckel.io/ntfy/v2/db"
)
// Timestamps come from the database clock, never from a node's (see Store). The upsert is one
// Timestamps come from the database clock, never from a node's (see Store), rounded down to the
// second like SQLite's. The upsert is one
// fixed statement per chunk (unnest), because SQL built per call bloats pgx's statement cache.
// Same period: add; a newer one: replace; an older one (a leftover): add to the stored period.
const (
postgresSelectClockQuery = `SELECT EXTRACT(EPOCH FROM now())::BIGINT`
postgresSelectClockQuery = `SELECT FLOOR(EXTRACT(EPOCH FROM now()))::BIGINT`
postgresSelectSinceQuery = `SELECT key, period_start, messages, emails, calls FROM usage WHERE updated_at >= $1`
postgresUpsertQuery = `
INSERT INTO usage AS u (key, period_start, messages, emails, calls, updated_at)
SELECT key, ps, m, e, c, EXTRACT(EPOCH FROM now())::BIGINT
SELECT key, ps, m, e, c, FLOOR(EXTRACT(EPOCH FROM now()))::BIGINT
FROM unnest($1::TEXT[], $2::BIGINT[], $3::BIGINT[], $4::BIGINT[], $5::BIGINT[]) AS d(key, ps, m, e, c)
ON CONFLICT (key) DO UPDATE SET
messages = CASE WHEN u.period_start >= EXCLUDED.period_start THEN u.messages + EXCLUDED.messages ELSE EXCLUDED.messages END,
+26
View File
@@ -212,3 +212,29 @@ func keysOf(rows map[string]usageRow) []string {
slices.Sort(keys)
return keys
}
func TestStore_ClockTruncatesToTheSecond(t *testing.T) {
// Database time is whole seconds, rounded down on both dialects, for the clock and for
// updated_at alike (the test database runs on this host's clock)
forEachBackend(t, func(t *testing.T, newStore func() *Store) {
s := newStore()
ctx := context.Background()
for i := 0; i < 20; i++ {
dbNow, err := s.clock(ctx)
require.Nil(t, err)
require.LessOrEqual(t, dbNow, time.Now().Unix())
_, err = s.write(ctx, []usageRow{
{
key: "k",
periodStart: 1,
counts: [numDaily]int64{1, 0, 0},
},
})
require.Nil(t, err)
var updatedAt int64
require.Nil(t, s.db.QueryRow(`SELECT updated_at FROM usage WHERE key = 'k'`).Scan(&updatedAt))
require.LessOrEqual(t, updatedAt, time.Now().Unix())
time.Sleep(37 * time.Millisecond)
}
})
}