Preview: Verfolger-Wettlauf bei neuen Projekten behoben

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-01 11:10:54 +00:00
1 parent d416a7aa09
commit b193b327ab
2 files changed
+33 -2

No files matched your search

+19 -2
View File
@@ -542,7 +542,7 @@ export async function syncPreviewTlsOnStartup({
// Zeiten des Hintergrund-Verfolgers (fuer Tests ueberschreibbar)
const NO_DEV_SCRIPT_ERROR = 'Kein dev-Skript in package.json'
export const runnerTiming = { pollMs: 2000, maxMs: 60 * 60 * 1000, unreachableMs: 5 * 60 * 1000 }
export const runnerTiming = { pollMs: 2000, maxMs: 60 * 60 * 1000, unreachableMs: 5 * 60 * 1000, docWaitMs: 15000, docPollMs: 50 }
// Neuester Lauf je Repo: aeltere Verfolger schreiben nichts mehr (R14)
const latestRun = new Map()
const followers = new Set()
@@ -600,6 +600,20 @@ function clampAttrs(data) {
return out
}
/**
* Neues Projekt: der Webhook legt das Dokument erst NACH runDeploy an. Ein schneller Verfolger
* findet es dann noch nicht - kurz auf die Anlage warten, sonst geht sein Ergebnis verloren.
*/
async function waitForProject(repoFullName, project) {
if (project?.$id) return project
const until = Date.now() + runnerTiming.docWaitMs
for (;;) {
const doc = await findProject(repoFullName)
if (doc || Date.now() >= until) return doc || project
await new Promise((r) => setTimeout(r, runnerTiming.docPollMs))
}
}
async function patchProject(repoFullName, project, data) {
data = clampAttrs(data)
const doc = project?.$id ? project : await findProject(repoFullName)
@@ -649,8 +663,11 @@ async function followRun({ repoFullName, project, token, runId, subdomain, job,
}
if (!current()) return
project = await waitForProject(repoFullName, project)
if (!current()) return
if (run?.log?.length) {
try { await saveRunLog((project?.$id || (await findProject(repoFullName))?.$id), run.log, env) } catch (err) {
try { await saveRunLog(project?.$id, run.log, env) } catch (err) {
console.error('[previewDeploy] Protokoll speichern fehlgeschlagen:', err.message)
}
}
+14
View File
@@ -132,6 +132,20 @@ test('C1: neues Projekt per Push wird nach Verfolger-Erfolg bereit', async () =>
assert.equal(d.provisioningStatus, 'ready')
})
test('C1: Verfolger ist vor der Anlage des Projektdokuments fertig -> Ergebnis geht nicht verloren', async () => {
const { createDocument } = await import('../server/services/appwriteAdmin.js')
rs.script = done()
await pd.runDeploy('WEBklar/spaet', 'main', { subdomain: 'spaet', type: 'static', branch: 'main' }, { sha: SHA })
// Webhook legt das Dokument erst nach dem Lauf an (simulierte Verzoegerung, Lauf ist nach ~10 ms fertig)
await new Promise((r) => setTimeout(r, 80))
await createDocument('websiteProjects', { repoFullName: 'WEBklar/spaet', projectName: 'S', subdomain: 'spaet', status: 'pending', provisioningStatus: 'pending' }, 'spaet')
await pd.waitForRunFollowers()
const d = aw.get('websiteProjects', 'spaet')
assert.equal(d.provisioningStatus, 'ready')
assert.equal(d.status, 'deployed')
assert.equal(d.previewState, 'online')
})
test('C1: deployKeepsStatus nur mit Runner an', () => {
assert.equal(pd.deployKeepsStatus({ deployed: false, queued: true }), true)
assert.equal(pd.deployKeepsStatus({ deployed: false, skipped: true }), true)