Skip to content

fix: enforce single-instance using QLockFile#117

Merged
ErikBjare merged 3 commits intoActivityWatch:masterfrom
TimeToBuildBob:bob/single-instance-enforcement
Feb 27, 2026
Merged

fix: enforce single-instance using QLockFile#117
ErikBjare merged 3 commits intoActivityWatch:masterfrom
TimeToBuildBob:bob/single-instance-enforcement

Conversation

@TimeToBuildBob
Copy link
Contributor

@TimeToBuildBob TimeToBuildBob commented Feb 27, 2026

Summary

Prevents multiple instances of aw-qt from running simultaneously by using Qt's built-in QLockFile.

  • On startup, aw-qt acquires a lock file in the aw-qt data directory
  • If a lock is already held, the new instance logs a warning (with the running PID) and exits with code 1
  • Testing mode uses a separate lock file (aw-qt-testing.lock) to avoid conflicts with a production instance

Implementation

QLockFile from PyQt6.QtCore was chosen because:

  • Cross-platform (Windows, macOS, Linux) without additional dependencies
  • Already available since PyQt6 is an existing dependency
  • Designed exactly for this use case — includes PID/hostname/process name in the lock file for diagnostics
  • Handles stale lock cleanup automatically

The lock is acquired after logging is set up (so the warning lands in the log file) but before modules are started (so no partial startup occurs).

Related

Fixes ActivityWatch/activitywatch#1176

cc @ErikBjare


Important

Prevents multiple aw-qt instances using QLockFile, logging a warning and exiting if another instance is running.

  • Behavior:
    • Prevents multiple aw-qt instances using QLockFile in main.py.
    • Logs a warning and exits with code 1 if another instance is running.
    • Uses aw-qt-testing.lock for testing mode to avoid conflicts.
  • Implementation:
    • Adds _acquire_single_instance_lock() function in main.py to handle lock acquisition.
    • Lock acquired after logging setup but before module startup.
  • Misc:

This description was created by Ellipsis for 827d660. You can customize this summary. It will automatically update as commits are pushed.

Uses Qt's cross-platform QLockFile to prevent multiple instances of
aw-qt from running simultaneously. When a second launch is attempted,
it logs a warning (including the PID of the existing instance) and
exits with code 1.

Testing mode gets its own lock file so it doesn't conflict with a
normal production instance.

Fixes ActivityWatch/activitywatch#1176
Copy link

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed everything up to 827d660 in 6 seconds. Click for details.
  • Reviewed 58 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_WSmqMFjeCPyzsfIo

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

"""
import aw_core.dirs

data_dir = aw_core.dirs.get_data_dir("aw-qt")
Copy link
Member

Choose a reason for hiding this comment

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

Data dir? Why not cache dir?

@greptile-apps
Copy link

greptile-apps bot commented Feb 27, 2026

Greptile Summary

Adds single-instance enforcement to aw-qt using Qt's QLockFile, preventing multiple instances from running simultaneously.

  • Uses QLockFile from PyQt6.QtCore for cross-platform compatibility without additional dependencies
  • Lock is acquired after logging setup but before module startup, ensuring proper error reporting and preventing partial initialization
  • Testing mode uses a separate lock file (aw-qt-testing.lock) to avoid conflicts with production instances
  • When a second instance is attempted, it logs the PID of the running instance and exits cleanly with code 1
  • Lock is held for the entire process lifetime and automatically handles stale lock cleanup when processes crash

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The implementation uses Qt's well-tested QLockFile API with appropriate error handling and doesn't modify any existing functionality—it only adds single-instance enforcement at the appropriate point in the startup sequence
  • No files require special attention

Important Files Changed

Filename Overview
aw_qt/main.py Added single-instance enforcement using QLockFile to prevent multiple aw-qt processes from running simultaneously

Last reviewed commit: 827d660

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

1 file reviewed, no comments

Edit Code Review Agent Settings | Greptile

@TimeToBuildBob TimeToBuildBob mentioned this pull request Feb 27, 2026
@ErikBjare ErikBjare merged commit 7967ff8 into ActivityWatch:master Feb 27, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

App allows to execute multiple instances

2 participants