Preview-Deploy: gleichzeitige Deploys desselben Repos nacheinander

Projektaenderung und Gitea-Webhook deployten Kirschner Gebaeudeservice
am 30.09.2026 gleichzeitig; beide git clone liefen ins selbe
preview-data-Verzeichnis und brachen ab. runDeploy sperrt jetzt je
Arbeitsverzeichnis und Subdomain (keyedLock), andere Repos laufen
weiter parallel. Test stellt drei gleichzeitige Deploys nach.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-09-30 20:02:42 +00:00
1 parent d4241d20c4
commit edef85c7b3
2 files changed
+67 -1

No files matched your search

+56
View File
@@ -0,0 +1,56 @@
import { test, before, after } from 'node:test'
import assert from 'node:assert/strict'
import { execFileSync } from 'node:child_process'
import fs from 'node:fs/promises'
import os from 'node:os'
import path from 'node:path'
// 2026-09-30 (Kirschner Gebäudeservice): Projektänderung und Gitea-Webhook deployten dasselbe
// Repo gleichzeitig, beide git clone liefen ins selbe Arbeitsverzeichnis und brachen ab.
let tmp
let previewDeploy
const cwd = process.cwd()
before(async () => {
tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'preview-lock-'))
const repo = path.join(tmp, 'gitea', 'WEBklar', 'kunde.git')
const src = path.join(tmp, 'src')
await fs.mkdir(src, { recursive: true })
// Genug Inhalt, dass ein Klon Zeit braucht und sich zwei Klone überschneiden
for (let i = 0; i < 300; i += 1) await fs.writeFile(path.join(src, `seite-${i}.html`), `<p>${i}</p>`.repeat(200))
await fs.writeFile(path.join(src, 'index.html'), '<title>Kunde</title>')
const git = (args, dir) => execFileSync('git', args, { cwd: dir, stdio: 'ignore' })
git(['init', '-q', '-b', 'main'], src)
git(['-c', 'user.name=t', '-c', 'user.email=t@t', 'add', '.'], src)
git(['-c', 'user.name=t', '-c', 'user.email=t@t', 'commit', '-q', '-m', 'init'], src)
git(['clone', '-q', '--bare', src, repo], tmp)
await fs.mkdir(path.join(tmp, 'work'))
process.chdir(path.join(tmp, 'work')) // previewWorkDir() liegt unter process.cwd()
Object.assign(process.env, {
APPWRITE_ENDPOINT: 'http://127.0.0.1:9/v1',
APPWRITE_API_KEY: 'test-key',
GITEA_BASE_URL: `file://${path.join(tmp, 'gitea')}`,
GITEA_API_TOKEN: '',
PREVIEW_DEPLOY_ROOT: path.join(tmp, 'previews'),
TRAEFIK_DYNAMIC_DIR: '',
})
previewDeploy = await import('../server/services/previewDeploy.js')
})
after(async () => {
process.chdir(cwd)
await fs.rm(tmp, { recursive: true, force: true })
})
test('gleichzeitige Deploys desselben Repos laufen nacheinander und gelingen beide', async () => {
const cfg = { subdomain: 'kunde', type: 'static' }
const results = await Promise.allSettled([
previewDeploy.runDeploy('WEBklar/kunde', 'main', cfg),
previewDeploy.runDeploy('WEBklar/kunde', 'main', cfg),
previewDeploy.runDeploy('WEBklar/kunde', 'main', cfg),
])
for (const r of results) assert.equal(r.status, 'fulfilled', r.reason?.message)
assert.match(await fs.readFile(path.join(tmp, 'previews', 'kunde', 'index.html'), 'utf8'), /Kunde/)
assert.equal((await fs.readdir(path.join(tmp, 'previews', 'kunde'))).filter((f) => f.startsWith('seite-')).length, 300)
})