Feat/native(chore): restart controls - #748
Merged
Vidarte-Alberto merged 24 commits intoSep 10, 2026
Merged
Conversation
…Restart for any supervised process.
…t actually restarts.
…server as service-managed.
…t instead of a GitHub release.
…tself internally.
… wrapper isn't published yet.
Vidarte-Alberto
marked this pull request as ready for review
September 9, 2026 05:18
Sharmaz
reviewed
Sep 10, 2026
Comment on lines
+41
to
+43
| const state = { ...defaults, ...overrides }; | ||
| jest.spyOn(useSystemRestartHook, "useSystemRestart").mockReturnValue(state); | ||
| return state; |
Collaborator
There was a problem hiding this comment.
Avoid generic variables as state in the all file.
Sharmaz
reviewed
Sep 10, 2026
Comment on lines
+35
to
+39
| const { result } = renderHook(() => useSystemRestart()); | ||
|
|
||
| await act(async () => { | ||
| await result.current.loadRestartCapabilities(); | ||
| }); |
Collaborator
There was a problem hiding this comment.
Avoid generic variables as result in the whole document.
Sharmaz
reviewed
Sep 10, 2026
Comment on lines
+62
to
+64
| let returnValue; | ||
| await act(async () => { | ||
| returnValue = await result.current.restartServer(); |
Collaborator
There was a problem hiding this comment.
Be more specific with the variable names returnValue is meaningless
Sharmaz
reviewed
Sep 10, 2026
| val deadProcess = ProcessBuilder("true").start() | ||
| deadProcess.waitFor() | ||
| val pidFile = newPidFile().apply { writeText(deadProcess.pid().toString()) } | ||
| val service = PhoenixdProcessService(pidFile = pidFile) |
Collaborator
There was a problem hiding this comment.
Avoid generic variables as service in the whole document.
Sharmaz
reviewed
Sep 10, 2026
| @Test | ||
| fun `isLocalPhoenixd is false when phoenixd-remote is enabled`() = | ||
| testApplication { | ||
| environment { config = MapApplicationConfig("phoenixd-remote" to "true") } |
Collaborator
There was a problem hiding this comment.
Avoid generic variables as config in the whole document.
Collaborator
Author
There was a problem hiding this comment.
Config here isn't a local variable we're naming, it's the config property on Ktor's ApplicationEngineEnvironmentBuilder, set via the environment { config = ... } test DSL (ktor-server-test-host).
Sharmaz
requested changes
Sep 10, 2026
… start before the backend is ready.
ca-ruz
approved these changes
Sep 10, 2026
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.







Problem
Ambrosia had no way to restart the server or phoenixd from the app itself. If either process needed to pick up a config change, recover from a stuck state, or apply a pending settings change, the only options were a manual terminal/systemctl command (native installs), physically rebooting the device (hardware), or restarting containers by hand (Docker) — with zero in-app control. Electron already had the plumbing for this internally (
services:restartIPC), but it was never exposed as an actual button, and no other deployment mode had anything at all.Fix
Added "Restart server" / "Restart phoenixd" controls to Settings, working across every deployment mode — native (systemd), the Raspberry Pi/OrangePi hardware image, Docker, and Electron — by reusing each mode's own existing process supervisor (systemd
Restart=always, Dockerrestart: unless-stopped, Electron'sServiceManager) instead of introducing new privileges like passwordless sudo or polkit rules. phoenixd is signalled directly via a pidfile since it runs as the same OS user as the server on native/hardware installs; on Docker it correctly has no way to be reached (separate container, separate PID namespace) so only the server button is shown there.What Changed
canRestartSelf()/isSystemdManaged()/isLocalPhoenixd()server helpers to detect when a self-restart is safe.scheduleDockerRestart) intoscheduleProcessRestart, now also used for systemd-managed native/hardware installs.exitProcessafter stopping the embedded server — a leaked non-daemon thread from the Web Push async HTTP client was silently keeping the JVM alive afterstopSuspend(), so the process never actually restarted.PhoenixdProcessService, which signals phoenixd through a pidfile./system/restart-capabilities,/system/restart-server,/system/restart-phoenixdendpoints.run-server.sh/run-phoenixd.shself-restart wrappers with signal forwarding, sosystemctl stopstill stops the process cleanly instead of fighting the restart loop.AMBROSIA_SERVICE_MANAGEDflag intoinstall.shand the hardware image's systemd units.install.sh --localflag that builds and installs from the current checkout instead of downloading a GitHub release; updateduninstall.shto remove the new wrapper too.SeedGenerator(a stray triple-quoted string embedded newlines into the URL) that broke server boot on any fresh install without the local wordlist file, and the Docker client not binding to0.0.0.0, which made its own middleware unable to reach itself for the onboarding check.How to Test
./scripts/install.sh --local --yes, log in as admin, go to Settings → System, click "Restart server" and confirm — the service should actually come back. Same for "Restart phoenixd".docker compose up --build -d, confirm only "Restart server" is shown (not phoenixd), and that clicking it restarts theambrosiacontainer.services:restartIPC channel.--no-serviceinstall).Verification
./gradlew test ktlintCheckpassed.bash -n.Screenshots