History

fix(service): make install reconcile current service

t3-code[bot] committed 2 months ago

Commit f98cfca1 parent f708f633 files · +62 −38Browse files

Unified · Split

3 files
  1. apps/server/src/cli/service.test.ts +36 −1
  2. apps/server/src/cli/service.ts +22 −30
  3. docs/user/background-service.md +4 −7
apps/server/src/cli/service.test.ts+36−1
@@ -1,6 +1,8 @@
11 import { assert, it } from "@effect/vitest";
2+import * as Effect from "effect/Effect";
23
3−import { formatServiceStatus } from "./service.ts";
4+import * as BootService from "../cloud/bootService.ts";
5+import { formatServiceStatus, reconcileService } from "./service.ts";
46
57 const status = {
68 supported: true,
@@ -35,3 +37,36 @@ it("explains where the service is supported", () => { · 28 unmodified lines
3537 "Supported on: Linux with systemd, macOS with launchd",
3638 );
3739 });
40+
41+it.effect("restarts an already-current service during reconciliation", () =>
42+ Effect.gen(function* () {
43+ let installCount = 0;
44+ const plan = {
45+ nodePath: "/usr/bin/node",
46+ launcherPath: "/home/me/.t3/runtime/service-launcher.mjs",
47+ baseDir: "/home/me/.t3",
48+ logPath: status.logPath,
49+ unitPath: status.unitPath,
50+ };
51+ const service = BootService.BootService.of({
52+ status: Effect.succeed(status),
53+ install: Effect.sync(() => {
54+ installCount += 1;
55+ return plan;
56+ }),
57+ uninstall: Effect.succeed(false),
58+ });
59+
60+ const result = yield* reconcileService().pipe(
61+ Effect.provideService(BootService.BootService, service),
62+ );
63+
64+ assert.equal(installCount, 1);
65+ assert.deepEqual(result, {
66+ changed: true,
67+ previouslyInstalled: true,
68+ previouslyCurrent: true,
69+ plan,
70+ });
71+ }),
72+);
apps/server/src/cli/service.ts+22−30
@@ -18,28 +18,22 @@ export const bootServiceLayer = (config: ServerConfig.ServerConfig["Service"]) = · 17 unmodified lines
1818 cliVersion: packageJson.version,
1919 }).pipe(Layer.provide(ProcessRunner.layer));
2020
21−export type ServiceReconcileResult =
22− | {
23− readonly changed: false;
24− readonly status: BootService.BootServiceStatus;
25− }
26− | {
27− readonly changed: true;
28− readonly previouslyInstalled: boolean;
29− readonly plan: BootService.BootServicePlan;
30− };
21+export interface ServiceReconcileResult {
22+ readonly changed: true;
23+ readonly previouslyInstalled: boolean;
24+ readonly previouslyCurrent: boolean;
25+ readonly plan: BootService.BootServicePlan;
26+}
3127
3228 /** Install, update, or repair the service using the CLI version running this command. */
3329 export const reconcileService = Effect.fn("cli.service.reconcile")(function* () {
3430 const service = yield* BootService.BootService;
3531 const status = yield* service.status;
36− if (status.installed && status.current) {
37− return { changed: false, status } satisfies ServiceReconcileResult;
38− }
3932 const plan = yield* service.install;
4033 return {
4134 changed: true,
4235 previouslyInstalled: status.installed,
36+ previouslyCurrent: status.current,
4337 plan,
4438 } satisfies ServiceReconcileResult;
4539 });
@@ -79,14 +73,13 @@ const serviceInstallCommand = Command.make("install", projectLocationFlags).pipe · 33 unmodified lines
7973 flags,
8074 Effect.gen(function* () {
8175 const result = yield* reconcileService();
82− if (!result.changed) {
83− yield* Console.log(
84− `T3 Code service is already installed with t3@${packageJson.version}.`,
85− );
86− return;
87− }
76+ const action = result.previouslyCurrent
77+ ? "Restarted"
78+ : result.previouslyInstalled
79+ ? "Updated and restarted"
80+ : "Installed and started";
8881 yield* Console.log(
89− `${result.previouslyInstalled ? "Updated" : "Installed"} T3 Code service with t3@${packageJson.version}.\nLogs: ${result.plan.logPath}`,
82+ `${action} T3 Code service with t3@${packageJson.version}.\nLogs: ${result.plan.logPath}`,
9083 );
9184 }),
9285 ),
@@ -102,12 +95,13 @@ const serviceUpdateCommand = Command.make("update", projectLocationFlags).pipe( · 9 unmodified lines
10295 flags,
10396 Effect.gen(function* () {
10497 const result = yield* reconcileService();
105− if (!result.changed) {
106− yield* Console.log(`T3 Code service is already using t3@${packageJson.version}.`);
107− return;
108− }
98+ const action = result.previouslyCurrent
99+ ? "Restarted"
100+ : result.previouslyInstalled
101+ ? "Updated and restarted"
102+ : "Installed and started";
109103 yield* Console.log(
110− `${result.previouslyInstalled ? "Updated" : "Installed"} T3 Code service with t3@${packageJson.version}.\nLogs: ${result.plan.logPath}`,
104+ `${action} T3 Code service with t3@${packageJson.version}.\nLogs: ${result.plan.logPath}`,
111105 );
112106 }),
113107 ),
@@ -172,11 +166,9 @@ export const offerServiceDuringOnboarding = Effect.gen(function* () { · 58 unmodified lines
172166 return false;
173167 }
174168 const result = yield* reconcileService();
175− if (result.changed) {
176− yield* Console.log(
177− `Background service ${result.previouslyInstalled ? "updated" : "installed"}. Logs: ${result.plan.logPath}`,
178− );
179− }
169+ yield* Console.log(
170+ `Background service ${result.previouslyInstalled ? "updated" : "installed"}. Logs: ${result.plan.logPath}`,
171+ );
180172 return true;
181173 });
182174
docs/user/background-service.md+4−7
@@ -11,25 +11,22 @@ Install it with the latest T3 Code release: · 10 unmodified lines
1111 npx t3@latest service install
1212 ```
1313
14+The same command repairs and restarts an existing service, so there is no separate restart step.
15+
1416 Check whether it is installed:
1517
1618 ```sh
1719 npx t3@latest service status
1820 ```
1921
20−Update or repair it:
21−
22−```sh
23−npx t3@latest service update
24−```
25−
2622 Stop it and remove it from startup:
2723
2824 ```sh
2925 npx t3@latest service uninstall
3026 ```
3127
32−Updating restarts T3 Code briefly. Let active agent work and terminal commands finish first.
28+Repairing with `service install` restarts T3 Code briefly. Let active agent work and terminal
29+commands finish first.
3330 If a remote update is already in progress, wait for it to finish before retrying a local update.
3431
3532 The service runs a small stable launcher. Exact T3 Code versions are installed separately, so a