fix(desktop): claim the instance before application startup - #2875
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related issue
N/A - maintainer-requested improvement to Community desktop instance lifecycle.
Summary
Community currently checks for an existing instance while starting the window, after configuration and encryption initialization. Duplicate launches without arguments do not activate the existing window, and simultaneous file-open requests can overwrite the shared IPC file. Claim the instance at application entry and hand each launch request to the owner through an acknowledged local connection.
Keep the existing whole-file
app.lockuntil process exit, including shutdown hooks. A launch lock serializes receiver initialization and endpoint publication. The owner listens on a random port bound only to127.0.0.1; its endpoint contains the owner PID, process start time, and a random token. A duplicate sends one length-prefixed file/protocol argument or an empty activation request and exits only after the owner confirms receipt into its memory queue. Receiver operation is independent of frontend readiness or blocked window dispatch. Registration has one two-minute budget including launch-lock acquisition; each received frame has a two-second total budget, and forwarding has a five-second limit within the remaining registration budget. Ambiguous writes are never retried automatically.Instance admission belongs to the application entry point; the window no longer registers the instance again. A received request remains owned until its window callback finishes on the Swing EDT. Exit confirmation is rejected if a launch arrived during confirmation or a window handoff remains pending. Initial startup can still be cancelled before readiness when no forwarded request is waiting. Once exit starts, new launchers wait for the old instance lock to be released before initializing services. Failed or rejected exit actions restore admission and dispatch, including late readiness and unread legacy requests. Invalid launch arguments retain the existing logged error outcome and cannot permanently block later launches or exit. CLI, headless services, and macOS native activation keep their existing runtime paths.
Legacy
app.ipcfile/protocol forwarding remains available for older binaries. Its reader retains timestamp-collision handling and retries transient failures independently of new requests. All current-version launchers use the acknowledged connection, so simultaneous requests and identical repeated arguments do not overwrite or coalesce.Affected surfaces
Verification
-Dmaven.test.skip=false -DskipTests=false -Dmaven.test.failure.ignore=falseand explicitai.chat2db.community.jcef.**.*Test/ai.chat2db.community.tools.**.*Testselectors: 176 tests, 175 passed, 1 environment-dependent terminal test skipped; affected modules packaged successfully.SingleInstanceUtilTest: all 33 tests passed using separate JVMs, real OS locks and sockets. Coverage includes concurrent and repeated requests; pre-readiness and EDT-pending acknowledged requests during exit; stale close/restart/update confirmations; failed-exit and late-readiness recovery; cancellation of initial startup; real window-handler ordering with native operations replaced; unsupported/internal restart URIs; lock timeout/interruption; overlapping slow authentication/payload frames and healthy senders; crash recovery; and legacy compatibility. Test JVMs use isolated home directories and are joined before cleanup.mvn -B -o -f chat2db-community-server/pom.xml -pl :chat2db-community-start -am -Dmaven.test.skip=true -Dchat2db.finalName=chat2db-community package: executable backend packaged with tests skipped for this command.git diff --checkand workflow YAML parsing passed.Risk and compatibility
app.lockremains authoritative;app.launch.lockcoordinates launch initialization, andapp.ipc.endpointstores process-bound connection metadata. These files live in the existing per-user state directory. Exit actions must report whether exit started so failed attempts can restore admission.Reviewer map
SingleInstanceUtil.registerInstance,forward,receive,dispatch, andguardExit; then application entry, frontend readiness binding,MainJFrame.handleLaunchRequest, andApplicationExitCoordinator.Contributor declaration
AI assistance: Codex implemented and tested this change following the maintainer's diagnosis and requested design.