시간 도메인과 정지 중 메시지·베팅 경계 정리

This commit is contained in:
2026-09-03 16:01:19 +00:00
parent 10cddbb565
commit abceee8315
108 changed files with 3504 additions and 1473 deletions
@@ -2995,7 +2995,7 @@ export class GatewayOrchestrator implements GatewayOrchestratorHandle {
profile: GatewayProfileRecord,
assertLease?: () => Promise<void>
): Promise<boolean> {
const deadline = Date.now() + this.profileReadinessTimeoutMs;
const deadline = performance.now() + this.profileReadinessTimeoutMs;
const definitions = buildProcessDefinitions(profile, this.processConfig);
const expectedNames = Object.entries(definitions)
.filter(([role]) => this.frontendServeMode === 'preview' || role !== 'frontend')
@@ -3008,7 +3008,7 @@ export class GatewayOrchestrator implements GatewayOrchestratorHandle {
this.processConfig.frontendReadinessOrigin ?? 'http://caddy'
).toString()
: `http://127.0.0.1:${profile.apiPort - 1}/${profile.profile}/`;
while (Date.now() < deadline) {
while (performance.now() < deadline) {
await assertLease?.();
try {
const [api, frontend, processes] = await Promise.all([
@@ -242,13 +242,19 @@ export const createGatewayReleaseRepository = (prisma: GatewayPrismaClient): Gat
});
return mapOperation(row);
},
async claimNextOperation(now, lease) {
async claimNextOperation(_now, lease) {
const row = await prisma.$transaction(async (tx) => {
await tx.$queryRaw<Array<{ lock_result: string }>>`
SELECT pg_advisory_xact_lock(
hashtextextended(${CONTROL_PLANE_OPERATION_CLAIM_LOCK}, 0)
)::text AS lock_result
`;
const [{ now }] = await tx.$queryRaw<Array<{ now: Date }>>`
SELECT CURRENT_TIMESTAMP AS "now"
`;
if (!now) {
throw new Error('Database wall clock is unavailable while claiming a Gateway release operation.');
}
const runningProfileOperation = await tx.gatewayOperation.findFirst({
where: { status: 'RUNNING' },
select: { id: true },
@@ -326,13 +332,21 @@ export const createGatewayReleaseRepository = (prisma: GatewayPrismaClient): Gat
});
return row ? mapOperation(row) : null;
},
async renewOperationLease(id, ownerId, now, durationMs) {
const updated = await prisma.gatewayReleaseOperation.updateMany({
where: { id, status: 'RUNNING', leaseOwner: ownerId },
data: {
leaseUntil: new Date(now.getTime() + durationMs),
heartbeatAt: now,
},
async renewOperationLease(id, ownerId, _now, durationMs) {
const updated = await prisma.$transaction(async (tx) => {
const [{ now }] = await tx.$queryRaw<Array<{ now: Date }>>`
SELECT CURRENT_TIMESTAMP AS "now"
`;
if (!now) {
throw new Error('Database wall clock is unavailable while renewing a Gateway release lease.');
}
return tx.gatewayReleaseOperation.updateMany({
where: { id, status: 'RUNNING', leaseOwner: ownerId },
data: {
leaseUntil: new Date(now.getTime() + durationMs),
heartbeatAt: now,
},
});
});
return updated.count === 1;
},
@@ -691,7 +691,7 @@ export const createGatewayProfileRepository = (prisma: GatewayPrismaClient): Gat
return mapOperation(row);
},
async claimNextOperation(
now: Date,
_now: Date,
lease?: { ownerId: string; durationMs: number }
): Promise<GatewayOperationRecord | null> {
const row = await prisma.$transaction(async (tx) => {
@@ -700,6 +700,12 @@ export const createGatewayProfileRepository = (prisma: GatewayPrismaClient): Gat
hashtextextended(${CONTROL_PLANE_OPERATION_CLAIM_LOCK}, 0)
)::text AS lock_result
`;
const [{ now }] = await tx.$queryRaw<Array<{ now: Date }>>`
SELECT CURRENT_TIMESTAMP AS "now"
`;
if (!now) {
throw new Error('Database wall clock is unavailable while claiming a Gateway operation.');
}
const runningRelease = await tx.gatewayReleaseOperation.findFirst({
where: { status: 'RUNNING' },
select: { id: true },
@@ -815,13 +821,21 @@ export const createGatewayProfileRepository = (prisma: GatewayPrismaClient): Gat
});
return row ? mapOperation(row) : null;
},
async renewOperationLease(id: string, ownerId: string, now: Date, durationMs: number): Promise<boolean> {
const renewed = await prisma.gatewayOperation.updateMany({
where: { id, status: 'RUNNING', leaseOwner: ownerId },
data: {
leaseUntil: new Date(now.getTime() + durationMs),
heartbeatAt: now,
},
async renewOperationLease(id: string, ownerId: string, _now: Date, durationMs: number): Promise<boolean> {
const renewed = await prisma.$transaction(async (tx) => {
const [{ now }] = await tx.$queryRaw<Array<{ now: Date }>>`
SELECT CURRENT_TIMESTAMP AS "now"
`;
if (!now) {
throw new Error('Database wall clock is unavailable while renewing a Gateway operation lease.');
}
return tx.gatewayOperation.updateMany({
where: { id, status: 'RUNNING', leaseOwner: ownerId },
data: {
leaseUntil: new Date(now.getTime() + durationMs),
heartbeatAt: now,
},
});
});
return renewed.count === 1;
},