-
Notifications
You must be signed in to change notification settings - Fork 16
Separate UI and server into two processes & Implement windows installer #170
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Separate UI and server into two processes & Implement windows installer #170
Conversation
This refactors the Windows application to use a robust two-process architecture, separating the UI from the Kolibri server. This is a foundational change to improve stability, responsiveness, and enable future Windows-specific features like a background service. The architecture includes: - Process Spawning: The main executable now detects a `--run-as-server` flag to launch in a headless server mode. The UI process spawns this server as a hidden child process. - Job Object Lifecycle Management: The server subprocess is assigned to a Windows Job Object. This ensures the OS automatically and reliably terminates the server if the main UI application closes or crashes, preventing orphaned processes. - Named Pipe IPC: A pull-based handshake using named pipes is implemented for communication. The UI process requests connection information, and the server only responds after Kolibri has fully initialized, preventing startup race conditions. - POSIX Refactor: The existing single-process, threaded model for macOS and Linux has been refactored into `server_manager_posix.py` to preserve existing behavior and prevent regressions on non-Windows platforms. Partially addresses learningequality#167
ea07ad9 to
bf802e4
Compare
|
I think rebasing the branch to main worked (thumbs up emoji) |
- Implement Inno Setup installer script (kolibri.iss) for Windows deployment - Add Windows service installation option using NSSM (Non-Sucking Service Manager) - Include WebView2 runtime installer in setup package - Add service detection to UI process to connect to existing service instead of spawning subprocess - Configure KOLIBRI_HOME to use system-wide ProgramData folder for production builds - Add installer build targets to Makefile (build-installer-windows, codesign-installer-windows) - Implement upgrade/downgrade/repair logic in installer with version detection - Configure proper file permissions for service account (LocalService) and users - Add security descriptor for named pipe to allow UI-service communication The installer provides two installation modes: 1. Desktop application only 2. Windows service + desktop application Fixes learningequality#167
ozer550
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Iv'e tested the Pr locally. I noticed that if the Kolibri service is stopped via services.msc while the app is still running, the UI repeatedly shows "Disconnected from the server" and doesn’t recover. To get it working again, I had to manually close and reopen the app. Other than that some other code improvements and some other type hint issues.
rtibbles
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some questions - mostly just interested in how we can keep the architecture clean and avoid too many nested processes/threads/calls etc.
The `WindowsServerManager` can now handle two failure scenarios: 1. Service Disconnection: If the app is connected to the Kolibri Windows service and the service stops, the app will now attempt to reconnect a few times. If it fails, it will automatically fall back to launching a local server for the duration of the session, preventing the UI from getting stuck. 2. Local Server Crash: If the app is running its own local server process and that process crashes or terminates unexpectedly, it will now be automatically restarted.
…s, improve UX for downgrades - Change LocalService permissions from Full Control to Modify - Add path constants to reduce duplication - Define AppGuid and WebView2RuntimeGuid constants with MS documentation links - Downgrade detection message now shows both installed and installer versions - Fix NSSM path in UninstallRun to match actual installation location
This commit refactors the Windows server subprocess (`server_process.py` renamed to `server_process_windows.py`). - A new `WindowsIpcPlugin` now encapsulates all named pipe communication logic, replacing the previous manually managed `PipeServerThread`. - The plugin uses the `START`, `STOP`, and `SERVING` events from `KolibriProcessBus` to manage its lifecycle and state, ensuring cleaner setup and teardown. - The `ServerProcess` class is simplified to be an initializer for Kolibri and the bus/plugin. - Large methods within the plugin have been broken down into smaller, single-responsibility functions to improve readability. - Error handling is now more specific, replacing blanket `except Exception` clauses.
…anager_windows.py) - Decomposed the monolithic `_launch_server_process` and `_handle_pipe_error` methods into smaller, single-responsibility helper functions. - Replaced blanket `except Exception` clauses with specific exception types (e.g., `OSError`, `subprocess.SubprocessError`, `pywintypes.error`, `JSONDecodeError`).
…Dimi20cen/kolibri-app into feat/windows/separate-processes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ive tested the changes locally and all previously mentioned issues are now fixed. Commented some other suggestions that caught my eye.
A race condition could occur in the WindowsIpcPlugin where two threads could attempt to close the named pipe handle simultaneously. This could happen if a client disconnected at the same moment the server was shutting down, leading to an error. This change introduces a threading.Lock, preventing this scenario.
|
@pcenov @radinamatic the goal here is just to do a regression test on the Mac App asset - no need to do any testing of the (not yet complete) Windows App. If you find any regressions with the Mac App, please file as follow up issues, as @Dimi20cen doesn't have a Mac to develop on. |
|
Hi @rtibbles - I didn't observe any regressions caused by the changes made here while testing the Mac app. |
ozer550
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Nice work.
Summary
This pull request refactors the Kolibri Windows application to use a two-process architecture, separating the UI from the Kolibri server and introduces a Windows installer with optional service support. This is the part of a larger effort to modernize the Windows installer and application behavior.
Explanation of core changes (Windows):
Process Separation (UI vs. Server):
kolibri_app) now acts as a lightweight UI process, responsible only for thewxPythonwindow and webview. It spawns the Kolibri server as a separate, hidden child subprocess using the same executable but with a new--run-as-serverflag.Robust Lifecycle Management with Job Objects:
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE. That way, if the main UI process is closed or crashes, the operating system will terminate the server subprocess. This prevents orphaned or "zombie" Kolibri processes from being left behind.Reliable Startup Handshake with Named Pipes:
request_server_infomessage.Windows Installer with Service Support:
The existing in-process, thread-based behavior for macOS and Linux is preserved and refactored into
server_manager_posix.pyto ensure no regressions on those platforms.Code Pointers
WindowsServerManagerandPosixServerManagerand howstart_server()andshutdown()direct to the appropriate manager based on the OS.main()that routes execution toServerProcesswhen the--run-as-serverflag is present.build-installer-windows) and managing dependencies (WebView2, NSSM).References
Fixes #167, concerning the UI/Server Process seperation for Windows and implementing Windows Service
Reviewer guidance
The most critical area for review is the new Windows-specific logic, including both the process separation architecture and the installer/service functionality.
How to test on Windows:
make dependencies).make pyinstallerto build the application.dist/Kolibri-0.18.1/Kolibri-0.18.1.exeto test the standalone app.make build-installer-windows(requires Inno Setup installed)dist-installer/kolibri-setup-0.18.1.exePrimary focus for testing:
Standalone Application Tests:
Standard Startup & Shutdown:
Kolibri-0.18.1.exeandKolibriprocesses terminate completely within a few seconds. There should be no lingering processes.Robustness Test (Process Crash Simulation):
Kolibri-0.18.1.exeprocess and aKolibriprocess. (Kolibri-0.18.1.exeis the server andKolibriis the ui).Kolibri-0.18.1.exe) and manually terminate it ("End Task").Installer
Fresh Installation Tests
Upgrade/Downgrade Tests
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Kolibriand modify the value of "Version" to and older version e.g., 0.18.0Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Kolibriand modify the value of "Version" to and future version e.g., 0.18.2Service Management Tests
WebView2 Not Installed Test:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}"C:\Program Files (x86)\Microsoft\EdgeWebView\Application\138.0.3351.83\msedgewebview2.exe"msedgewebview2.exeshould be restored and the UI should workUninstallation Test:
sevices.msc- no Kolibri service should existC:\Program Files\Kolibriis removedC:\ProgramData\kolibriis removedDevelopment vs Production Path Tests
C:\ProgramData\kolibrimake run-devC:\Users\<user>\.kolibri_devSILENT and VERYSILENT Installation
kolibri-setup-0.18.1.exe /SILENTkolibri-setup-0.18.1.exe /VERYSILENTTesting on macOS/Linux (Regression Check):
mainbranch.