Repository navigation
Conversation
Trombo38
force-pushed
the
external-service-windows
branch
from
October 25, 2026 18:00
e78f465 to
c798ba1
Compare
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.
EXTERNAL_SERVICE on Windows (local process units)
What
EXTERNAL_SERVICEon an External API preset now works on Windows, not only Linux.Today the four platform hooks (
unitAction,unitActiveState,unitPIDs,waitGPUsReleased) are stubs on Windows that return"EXTERNAL_SERVICE n'est pris en charge que sous Linux"— so a preset that names aservice fails to switch on Windows instead of starting its engine.
This PR implements them on Windows with the same contract the Linux systemd units
already provide:
(
nvidia-smi --query-compute-apps=pid, ported fromsys_service_linux.go)before the next engine loads — so one engine owns the GPUs at a time.
On Windows the "unit" is a local process defined by a JSON file in
$AJEAN_HOME\services\ajean-<name>.json(the newservices/folder, created onfirst use — it does not exist in a current install):
{ "command": "I:\\Strata\\.venv\\Scripts\\python.exe", "args": ["I:\\Strata\\serve\\server.py", "--engine", "strata", "--config", "I:\\Strata\\strata-swift-iq2_xs.json", "--port", "8080"], "cwd": "I:\\Strata", "env": { "PYTHONUTF8": "1" } }command/cwdmay be relative (resolved from the file's folder);envis mergedover the inherited environment. The process is launched detached (same flags as
ajean serve), tracked by a PID file, logged to$AJEAN_HOME\<unit>.log, stoppedwith
taskkill /T /F— the exact primitives the local engine supervisor alreadyuses, no admin rights, no external tools.
The preset itself is unchanged and portable across platforms:
EXTERNAL_SERVICE=ajean-strata-iq2xs(same^ajean-[a-z0-9][a-z0-9-]{0,40}$regex).Why the GPU-mutex is safe
SwitchToPreset(backend_presets.go) already orders the calls correctly and thisPR does not change that path — it only makes the Windows hooks real:
serviceAction("restart")first (which on Windows +external config stops the local llama-server and waits for the port to free),
then
syncExternalServicestarts the external service.syncExternalServicestops the external unit,waitGPUsReleasedwaits for its PIDs to leave the GPU, then llama.cpp restarts.So the two engines never coexist — the Windows equivalent of the Linux
Conflicts=ajean-engine.service, obtained by call order.Files
internal/ajean/run.go—servicesDir()=$AJEAN_HOME\servicesinternal/ajean/sys_service_windows.go— remove the 4 "Linux only" stubsinternal/ajean/sys_service_windows_extservice.go(new) — the 4 hooksinternal/ajean/sys_service_windows_extservice_test.go(new) — def parsing,state tracking, GPU-mutex order (via
syncExternalService)internal/ajean/backend_extservice.go— doc comment updated (no behavior change)README.md/README.fr.md— "Third-party engine" section now Linux & WindowsTesting (CI gates)
gofmt -l .(Go 1.25) — clean.go vet ./...— clean.staticcheck@latest— 0 warnings (project is zero-warning).CGO_ENABLED=0— 4/4: linux/amd64, linux/arm64, windows/amd64, windows/arm64.go test ./...(withAJEAN_HOMEisolated) — all pass, exceptTestMoeMigratewhich fails on this Windows host due to a symlink privilege it does not have
("A required privilege is not held by the client"); it passes on the CI ubuntu
runner and is unrelated to this change (the PR touches no MoE or symlink code).
EXTERNAL_SERVICE/ external tests pass:TestSyncExternalService,TestSyncExternalServiceRejectsForeignUnits,TestExternalServiceReady,TestExternalPresetEditKeepsServiceAndMachine, plus the newTestExtServiceDefParsing,TestExtUnitStateTracking,TestWindowsExternalServiceMutex.services/ajean-e2e.jsonwas started viasyncExternalService, reachedexternalServiceReady(unit active +/health200), and was stopped cleanly(port no longer listening).