mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-15 15:02:04 +00:00
fix(backups): size the off-host ledger column for the object the uploader allows
The column was INTEGER. A single object may occupy 8 MiB across 10 000 multipart parts, which is the 80 GB the uploader explicitly permits, and Postgres INTEGER stops at 2.1 GB. An account between the two uploads fine and then cannot be recorded, so the biggest account on the host is the one the console would have to report on and could not. BIGINT in the table, BigInt in the model, Number() where the route builds the wire row so the payload type stays a plain number. The migration is edited in place rather than followed by a second one: the table has not shipped, and a column widened before its first release is one column, not a history. The comparison with the in-database backup does not carry over, for the record: that size is octet_length over a bytea Postgres caps at 1 GB, while this object never touches the database at all.
This commit is contained in:
1 parent
86823db34e
commit
e64435f6a5
7 files changed
+27
-12
No files matched your search
@@ -64,7 +64,9 @@ describe("GET /api/admin/backups — off-host freshness", () => {
|
||||
username: "account-one",
|
||||
offhostBackupState: {
|
||||
lastSuccessAt: new Date(now - 3 * HOUR),
|
||||
sizeBytes: 4096,
|
||||
// The column is BigInt — an object may be 80 GB — and the wire type
|
||||
// is a plain number.
|
||||
sizeBytes: BigInt(4096),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -72,7 +74,7 @@ describe("GET /api/admin/backups — off-host freshness", () => {
|
||||
username: "account-two",
|
||||
offhostBackupState: {
|
||||
lastSuccessAt: new Date(now - 30 * HOUR),
|
||||
sizeBytes: 8192,
|
||||
sizeBytes: BigInt(8192),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -80,7 +82,7 @@ describe("GET /api/admin/backups — off-host freshness", () => {
|
||||
username: "account-three",
|
||||
offhostBackupState: {
|
||||
lastSuccessAt: new Date(now - 100 * HOUR),
|
||||
sizeBytes: 128,
|
||||
sizeBytes: BigInt(128),
|
||||
},
|
||||
},
|
||||
{ id: "u4", username: "account-four", offhostBackupState: null },
|
||||
@@ -99,6 +101,7 @@ describe("GET /api/admin/backups — off-host freshness", () => {
|
||||
["account-four", "never"],
|
||||
]);
|
||||
expect(body.offhost.rows[0]?.sizeBytes).toBe(4096);
|
||||
expect(typeof body.offhost.rows[0]?.sizeBytes).toBe("number");
|
||||
expect(body.offhost.rows[0]?.ageHours).toBe(3);
|
||||
expect(body.offhost.rows[3]?.lastSuccessAt).toBeNull();
|
||||
expect(body.offhost.rows[3]?.sizeBytes).toBeNull();
|
||||
@@ -126,7 +129,7 @@ describe("GET /api/admin/backups — off-host freshness", () => {
|
||||
username: "account-one",
|
||||
offhostBackupState: {
|
||||
lastSuccessAt: new Date(),
|
||||
sizeBytes: 1,
|
||||
sizeBytes: BigInt(1),
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -112,7 +112,10 @@ export const GET = apiHandler(async () => {
|
||||
userId: account.id,
|
||||
username: account.username,
|
||||
lastSuccessAt: state?.lastSuccessAt.toISOString() ?? null,
|
||||
sizeBytes: state?.sizeBytes ?? null,
|
||||
// BigInt column -> number on the wire. The value is bytes of one
|
||||
// object, capped by the uploader at 80 GB, so it is nowhere near
|
||||
// Number.MAX_SAFE_INTEGER and JSON has no BigInt.
|
||||
sizeBytes: state ? Number(state.sizeBytes) : null,
|
||||
ageHours: verdict.ageHours,
|
||||
freshness: verdict.freshness,
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user