mirror of
https://gitea.com/gitea/act_runner.git
synced 2026-08-02 21:03:09 +00:00
Starting two runner daemons with the same `.runner` file makes both present an identical UUID+token, so Gitea treats them as one runner and they cancel each other's jobs. This adds a non-blocking advisory lock on a sibling `<runner-file>.lock`: the daemon (and `register`) acquire it at startup, and a second process on the same host fails fast with a clear error instead of silently interfering. The OS releases the lock when the process exits — including a hard kill — so no stale lock is left behind. Legitimate multi-runner setups are unaffected since each already uses its own `runner.file`. Note: this covers the common single-host case; two hosts sharing a copied `.runner` (e.g. over NFS) would still need server-side detection in Gitea. --------- Co-authored-by: Zettat123 <zettat123@gmail.com> Reviewed-on: https://gitea.com/gitea/runner/pulls/1099 Reviewed-by: Zettat123 <39446+zettat123@noreply.gitea.com>
37 lines
994 B
Go
37 lines
994 B
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
//go:build windows
|
|
|
|
package lock
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
// tryLock opens (creating if needed) the lock file and takes a non-blocking
|
|
// exclusive lock on it via LockFileEx. The returned release closes the file,
|
|
// which drops the lock; Windows also drops it when the process exits.
|
|
func tryLock(path string) (func() error, error) {
|
|
f, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0o600)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
handle := windows.Handle(f.Fd())
|
|
overlapped := new(windows.Overlapped)
|
|
if err := windows.LockFileEx(handle, windows.LOCKFILE_EXCLUSIVE_LOCK|windows.LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, overlapped); err != nil {
|
|
_ = f.Close()
|
|
if errors.Is(err, windows.ERROR_LOCK_VIOLATION) {
|
|
return nil, ErrLocked
|
|
}
|
|
return nil, err
|
|
}
|
|
return func() error {
|
|
_ = windows.UnlockFileEx(handle, 0, 1, 0, overlapped)
|
|
return f.Close()
|
|
}, nil
|
|
}
|