시간 도메인과 정지 중 메시지·베팅 경계 정리
This commit is contained in:
@@ -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;
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user