Skip to content

Панель зависает ~24с: /projects упирается в stale state git-lock (.docker-git.lock не переустанавливается) #448

Description

@skulidropek

Симптом

Панель грузится очень долго (десятки секунд). Изоляция показывает, что виноват один эндпоинт:

docker exec docker-git-api curl -s -o /dev/null -w '%{time_total}s' http://127.0.0.1:3334/health    # 0.001s
docker exec docker-git-api curl -s -o /dev/null -w '%{time_total}s' http://127.0.0.1:3334/projects   # 24s

В логах при этом непрерывный спам:

WARN: State auto-pull failed: state git lock (exit 75)

Первопричина

GET /projectslistProjects()readProjectItemsForInventory()refreshProjectStateForInventory() = autoPullState, обёрнутый в withStateGitLock.

Файловый лок берётся в acquireStateFileLock (packages/lib/src/usecases/state-repo/lock.ts):

const stateGitLockRetryDelay = Duration.millis(100)
const stateGitLockMaxAttempts = 50           // => до 5 секунд ожидания
const stateGitLockBusyExitCode = 75
const resolveStateLockPath = (root) => `${root}.lock`   // /home/dev/.docker-git.lock (каталог)

Проблема: stale-лок никак не детектируется и не переустанавливается. Если каталог-лок остался от аварийно завершённой/убитой git-операции (а контейнер docker-git-api за сессию рестартовал 4 раза), то каждая последующая state-операция:

  1. fs.makeDirectory(lockPath)AlreadyExists;
  2. ретраит 50×100мс = 5 секунд;
  3. падает с exit 75 (тот самый лог-спам).

Операции ещё и сериализуются через Effect.unsafeMakeSemaphore(1) и копятся в очередь, поэтому /projects ждёт суммарно ~24с.

В нашем случае были найдены два залипших лока:

/home/dev/.docker-git.lock            # каталог, возраст ~5.5 часов
/home/dev/.docker-git/.git/index.lock # 0 байт, возраст ~3 недели

Подтверждённый фикс (workaround)

docker exec -u 0 docker-git-api rm -rf /home/dev/.docker-git.lock /home/dev/.docker-git/.git/index.lock

Результат: /projects 24s → 0.16s (без рестарта). Спам exit 75 прекратился.

Предложение

  1. Детекция и авто-переустановка stale-лока в acquireStateFileLock: проверять возраст каталога-лока (mtime) и/или PID владельца, и переустанавливать лок по TTL вместо бесконечного упирания в него.
  2. Гарантированное снятие лока при аварийном завершении/рестарте процесса (cleanup on startup / signal handler) — сейчас крэш/kill оставляет вечный лок.
  3. Опционально — не завязывать hot-path чтения на этот лок (см. отдельный issue про autoPullState на read-пути).

Окружение

  • Контейнер docker-git-api (панель на 127.0.0.1:3334, реверс через nginx).
  • Диагностировано через host docker socket. Диск/CPU/RAM в норме — проблема чисто в логике state-лока.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions