Skip to content

BUG: make log rotation safe across Windows processes - #5303

Open
Ricardo-M-L wants to merge 1 commit into
xorbitsai:mainfrom
Ricardo-M-L:fix/windows-safe-log-rotation
Open

BUG: make log rotation safe across Windows processes#5303
Ricardo-M-L wants to merge 1 commit into
xorbitsai:mainfrom
Ricardo-M-L:fix/windows-safe-log-rotation

Conversation

@Ricardo-M-L

Copy link
Copy Markdown
Contributor

Summary

  • use msvcrt.locking on Windows while retaining fcntl.flock on POSIX
  • fall back to copy-and-truncate when Windows refuses to rename a live log file
  • persist a rotation generation and timed-rollover marker in the lock file so waiting processes do not rotate or overwrite the same archive again
  • share the coordination logic across size, timed, and combined handlers

Fixes #5284.

Validation

  • xinference/deploy/test/test_log_rotation.py: 35 passed
  • Black 25.1.0: clean
  • Ruff 0.15.22: clean

The regression tests simulate Windows lock and rename behavior on macOS, including two handlers racing on size and midnight rotation. A Windows host end-to-end run was not available.

@XprobeBot XprobeBot added the bug Something isn't working label Aug 8, 2026
@XprobeBot XprobeBot added this to the v3.x milestone Aug 8, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces cross-platform, cross-process log rotation safety by implementing a shared _SafeFileRotationMixin that uses platform-native file locking (msvcrt on Windows and fcntl on Unix) and tracks rotation state via a shared lock file. It updates the rotating file handlers to inherit from this mixin and adds comprehensive unit tests to verify the Windows fallback and rotation coordination. The feedback highlights a potential file descriptor leak in _acquire_rotation_lock if the locking mechanism raises an exception, suggesting wrapping the lock acquisition in a try...except block to ensure the file descriptor is closed.

Comment on lines +69 to +76
def _acquire_rotation_lock(self):
lock_fd = open(self._lock_path, "r+b")
if msvcrt is not None:
lock_fd.seek(0)
msvcrt.locking(lock_fd.fileno(), msvcrt.LK_LOCK, 1)
else:
fcntl.flock(lock_fd, fcntl.LOCK_EX)
return lock_fd

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If msvcrt.locking or fcntl.flock raises an exception (for example, due to a timeout or locking conflict), the newly opened lock_fd will be leaked because the caller's try...finally block in doRollover is not entered when _acquire_rotation_lock raises an exception. To prevent file descriptor leaks, wrap the locking logic in a try...except block and close lock_fd before re-raising the exception.

Suggested change
def _acquire_rotation_lock(self):
lock_fd = open(self._lock_path, "r+b")
if msvcrt is not None:
lock_fd.seek(0)
msvcrt.locking(lock_fd.fileno(), msvcrt.LK_LOCK, 1)
else:
fcntl.flock(lock_fd, fcntl.LOCK_EX)
return lock_fd
def _acquire_rotation_lock(self):
lock_fd = open(self._lock_path, "r+b")
try:
if msvcrt is not None:
lock_fd.seek(0)
msvcrt.locking(lock_fd.fileno(), msvcrt.LK_LOCK, 1)
else:
fcntl.flock(lock_fd, fcntl.LOCK_EX)
return lock_fd
except Exception:
lock_fd.close()
raise

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] Windows: log rotation crashes with WinError 32 because fcntl-based cross-process lock is a no-op

2 participants