mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 22:50:51 +00:00
chore(release): prepare v1.31.4
This commit is contained in:
1 parent
3ce6726646
commit
b38f41b99d
12 files changed
+99
-68
No files matched your search
@@ -274,6 +274,22 @@ export const POST = apiHandler(async (request: NextRequest) => {
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
// Keep channel reconciliation under the same identity locks as the device
|
||||
// row. Moving it after commit lets two first-time registrations race the
|
||||
// compound unique key and intermittently turns one valid request into 500.
|
||||
if (apnsToken) {
|
||||
await tx.notificationChannel.upsert({
|
||||
where: { userId_type: { userId: user.id, type: "APNS" } },
|
||||
create: {
|
||||
userId: user.id,
|
||||
type: "APNS",
|
||||
enabled: true,
|
||||
config: encrypt("{}"),
|
||||
},
|
||||
update: {},
|
||||
});
|
||||
}
|
||||
|
||||
return { id: device.id };
|
||||
});
|
||||
|
||||
@@ -292,22 +308,6 @@ export const POST = apiHandler(async (request: NextRequest) => {
|
||||
|
||||
const { id } = registration;
|
||||
|
||||
// Reconcile APNs channel state only after the canonical device transaction
|
||||
// commits. Config is an encrypted empty record by design — the per-device
|
||||
// token and environment live on the Device row.
|
||||
if (apnsToken) {
|
||||
await prisma.notificationChannel.upsert({
|
||||
where: { userId_type: { userId: user.id, type: "APNS" } },
|
||||
create: {
|
||||
userId: user.id,
|
||||
type: "APNS",
|
||||
enabled: true,
|
||||
config: encrypt("{}"),
|
||||
},
|
||||
update: {},
|
||||
});
|
||||
}
|
||||
|
||||
await auditLog("devices.register", {
|
||||
userId: user.id,
|
||||
details: {
|
||||
|
||||
@@ -42,9 +42,7 @@ describe("per-process database connection budget", () => {
|
||||
expect(getConnectionBudget()).toBe(20);
|
||||
expect(getPrismaPoolMax()).toBe(18);
|
||||
expect(getPgBossPoolMax()).toBe(2);
|
||||
expect(getPrismaPoolMax() + getPgBossPoolMax()).toBe(
|
||||
getConnectionBudget(),
|
||||
);
|
||||
expect(getPrismaPoolMax() + getPgBossPoolMax()).toBe(getConnectionBudget());
|
||||
});
|
||||
|
||||
it("uses the existing pool_timeout seconds for both pool constructors", () => {
|
||||
|
||||
@@ -3,9 +3,7 @@ import { beforeEach, describe, expect, it, vi, type Mock } from "vitest";
|
||||
interface MockBoss {
|
||||
start: Mock<() => Promise<unknown>>;
|
||||
stop: Mock<(options?: { graceful?: boolean }) => Promise<void>>;
|
||||
on: Mock<
|
||||
(event: string, handler: (error: Error) => void) => MockBoss
|
||||
>;
|
||||
on: Mock<(event: string, handler: (error: Error) => void) => MockBoss>;
|
||||
emitError(error: Error): void;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,10 +7,7 @@
|
||||
*/
|
||||
import { PgBoss } from "pg-boss";
|
||||
|
||||
import {
|
||||
getPgBossPoolMax,
|
||||
getPoolConnectionTimeoutMs,
|
||||
} from "@/lib/db";
|
||||
import { getPgBossPoolMax, getPoolConnectionTimeoutMs } from "@/lib/db";
|
||||
|
||||
const BOSS_KEY = "__healthlog_pgboss__" as const;
|
||||
const BOSS_START_KEY = "__healthlog_pgboss_start__" as const;
|
||||
@@ -36,7 +33,9 @@ function wait(ms: number): Promise<void> {
|
||||
return promise;
|
||||
}
|
||||
|
||||
function resolveRetryPolicy(options: ProducerStartOptions): ProducerRetryPolicy {
|
||||
function resolveRetryPolicy(
|
||||
options: ProducerStartOptions,
|
||||
): ProducerRetryPolicy {
|
||||
const maxAttempts = Math.max(
|
||||
1,
|
||||
Math.trunc(options.maxAttempts ?? PRODUCER_START_MAX_ATTEMPTS),
|
||||
@@ -52,7 +51,10 @@ function resolveRetryPolicy(options: ProducerStartOptions): ProducerRetryPolicy
|
||||
return { maxAttempts, baseDelayMs, maxDelayMs };
|
||||
}
|
||||
|
||||
function retryDelayMs(failedAttempt: number, policy: ProducerRetryPolicy): number {
|
||||
function retryDelayMs(
|
||||
failedAttempt: number,
|
||||
policy: ProducerRetryPolicy,
|
||||
): number {
|
||||
return Math.min(
|
||||
policy.maxDelayMs,
|
||||
policy.baseDelayMs * 2 ** Math.max(0, failedAttempt - 1),
|
||||
@@ -164,8 +166,7 @@ export async function startGlobalBossProducer(
|
||||
if (existing) return existing;
|
||||
|
||||
const starting = globalState[BOSS_START_KEY] as
|
||||
| Promise<PgBoss | null>
|
||||
| undefined;
|
||||
Promise<PgBoss | null> | undefined;
|
||||
if (starting) return starting;
|
||||
|
||||
const startPromise = startProducerAttempts(
|
||||
|
||||
Reference in new issue
Block a user