querysub 0.359.0 → 0.361.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/config.ts +6 -1
- package/src/deployManager/components/ServiceDetailPage.tsx +70 -1
- package/src/deployManager/components/ServicesListPage.tsx +1 -1
- package/src/deployManager/machineApplyMainCode.ts +50 -0
- package/src/deployManager/machineController.ts +15 -1
- package/src/deployManager/machineSchema.ts +1 -1
- package/src/diagnostics/logs/IndexedLogs/LogViewer3.tsx +21 -2
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycles.tsx +7 -2
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -22,7 +22,12 @@ let yargObj = parseArgsFactory()
|
|
|
22
22
|
// TODO: The bootstrapper is a single file. Maybe we shouldn't run the entire service just for that. Although... maybe it's fine, as services are light?
|
|
23
23
|
.option("bootstraponly", { type: "boolean", desc: "Don't register as an edge node, so we serve the bootstrap files, but we don't need up to date code because we are not used for endpoints or the UI." })
|
|
24
24
|
.option("notifyemails", { type: "array", desc: "The emails to notify when errors occur." })
|
|
25
|
-
.option("diskaudit", {
|
|
25
|
+
.option("diskaudit", {
|
|
26
|
+
type: "boolean",
|
|
27
|
+
// NOTE: I wanna see how long I can keep this on for. Eventually it's gonna become a problem and we're gonna have to turn it off. But for testing it's certainly useful as we don't know exactly what is gonna cause a problem. But it probably will be synchronization related, and every server does synchronization.
|
|
28
|
+
default: true,
|
|
29
|
+
desc: "Track all audit logs to disk. This might end up writing A LOT of data."
|
|
30
|
+
})
|
|
26
31
|
.argv
|
|
27
32
|
;
|
|
28
33
|
type QuerysubConfig = {
|
|
@@ -11,7 +11,7 @@ import { deepCloneJSON, nextId, sort } from "socket-function/src/misc";
|
|
|
11
11
|
import { InputLabel } from "../../library-components/InputLabel";
|
|
12
12
|
import { Button } from "../../library-components/Button";
|
|
13
13
|
import { isDefined } from "../../misc";
|
|
14
|
-
import { watchScreenOutput, stopWatchingScreenOutput } from "../machineController";
|
|
14
|
+
import { watchScreenOutput, stopWatchingScreenOutput, MachineController } from "../machineController";
|
|
15
15
|
import { getPathStr2 } from "../../path";
|
|
16
16
|
import { ATag, Anchor } from "../../library-components/ATag";
|
|
17
17
|
import { ScrollOnMount } from "../../library-components/ScrollOnMount";
|
|
@@ -38,6 +38,7 @@ export class ServiceDetailPage extends qreact.Component {
|
|
|
38
38
|
data: t.type(""),
|
|
39
39
|
callbackId: t.type(""),
|
|
40
40
|
}),
|
|
41
|
+
isKillingRolling: t.type(false),
|
|
41
42
|
});
|
|
42
43
|
|
|
43
44
|
|
|
@@ -103,6 +104,37 @@ export class ServiceDetailPage extends qreact.Component {
|
|
|
103
104
|
await stopWatchingScreenOutput({ callbackId });
|
|
104
105
|
});
|
|
105
106
|
}
|
|
107
|
+
|
|
108
|
+
private async killAllRollingServices(config: ServiceConfig) {
|
|
109
|
+
Querysub.commit(() => {
|
|
110
|
+
this.state.isKillingRolling = true;
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
Querysub.onCommitFinished(async () => {
|
|
114
|
+
try {
|
|
115
|
+
let uniqueMachineIds = Array.from(new Set(config.machineIds));
|
|
116
|
+
|
|
117
|
+
for (let machineId of uniqueMachineIds) {
|
|
118
|
+
let machineInfo = await MachineServiceController(SocketFunction.browserNodeId()).getMachineInfo.promise(machineId);
|
|
119
|
+
if (!machineInfo) continue;
|
|
120
|
+
|
|
121
|
+
let applyNodeId = machineInfo.applyNodeId;
|
|
122
|
+
await MachineController(applyNodeId).killRollingServices.promise({
|
|
123
|
+
serviceKey: config.parameters.key,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
} catch (e: any) {
|
|
127
|
+
Querysub.localCommit(() => {
|
|
128
|
+
this.state.saveError = `Error killing rolling services: ${e.message}`;
|
|
129
|
+
});
|
|
130
|
+
} finally {
|
|
131
|
+
Querysub.localCommit(() => {
|
|
132
|
+
this.state.isKillingRolling = false;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
106
138
|
private async updateConfig(updatedConfig: ServiceConfig): Promise<void> {
|
|
107
139
|
const selectedServiceId = selectedServiceIdParam.value;
|
|
108
140
|
if (!selectedServiceId) return;
|
|
@@ -151,6 +183,27 @@ export class ServiceDetailPage extends qreact.Component {
|
|
|
151
183
|
const configT = config;
|
|
152
184
|
const hasUnsavedChanges = !!this.state.unsavedChanges;
|
|
153
185
|
|
|
186
|
+
let rollingServiceCount = 0;
|
|
187
|
+
if (config.parameters.rollingWindow) {
|
|
188
|
+
let uniqueMachineIds = Array.from(new Set(config.machineIds));
|
|
189
|
+
for (let machineId of uniqueMachineIds) {
|
|
190
|
+
try {
|
|
191
|
+
let machineInfo = controller.getMachineInfo(machineId);
|
|
192
|
+
if (!machineInfo) continue;
|
|
193
|
+
|
|
194
|
+
let applyNodeId = machineInfo.applyNodeId;
|
|
195
|
+
let rollingInfo = MachineController(applyNodeId).getRollingServiceInfo({
|
|
196
|
+
serviceKey: config.parameters.key,
|
|
197
|
+
});
|
|
198
|
+
if (rollingInfo) {
|
|
199
|
+
rollingServiceCount += rollingInfo.length;
|
|
200
|
+
}
|
|
201
|
+
} catch (e: any) {
|
|
202
|
+
console.error(`Error getting rolling service info for machine ${machineId}: ${e.message}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
154
207
|
// Sort machines by status and heartbeat
|
|
155
208
|
let nextIndexes = new Map<string, number>();
|
|
156
209
|
let machineStatuses = config.machineIds.map(machineId => {
|
|
@@ -432,6 +485,22 @@ export class ServiceDetailPage extends qreact.Component {
|
|
|
432
485
|
Poke
|
|
433
486
|
</button>
|
|
434
487
|
|
|
488
|
+
{configT.parameters.rollingWindow && rollingServiceCount > 0 && <button
|
|
489
|
+
className={css.pad2(12, 8).button.bord2(0, 0, 20).hsl(0, 70, 90)}
|
|
490
|
+
onClick={() => {
|
|
491
|
+
void this.killAllRollingServices(config);
|
|
492
|
+
}}
|
|
493
|
+
disabled={this.state.isKillingRolling}
|
|
494
|
+
>
|
|
495
|
+
{this.state.isKillingRolling ? "Killing..." : `💀 Kill ${rollingServiceCount} Rolling Service${rollingServiceCount === 1 ? "" : "s"}`}
|
|
496
|
+
</button>}
|
|
497
|
+
|
|
498
|
+
{configT.parameters.rollingWindow && <div>
|
|
499
|
+
<div className={css.colorhsl(0, 50, 50).fontSize(14).fontWeight("bold")}>
|
|
500
|
+
IMPORTANT! Service has a rolling window, so updates might not appear immediately.
|
|
501
|
+
</div>
|
|
502
|
+
</div>}
|
|
503
|
+
|
|
435
504
|
{hasUnsavedChanges && <>
|
|
436
505
|
<Button
|
|
437
506
|
flavor="noui"
|
|
@@ -136,7 +136,7 @@ export class ServicesListPage extends qreact.Component {
|
|
|
136
136
|
</div>
|
|
137
137
|
<div className={css.vbox(4)}>
|
|
138
138
|
<div>Updated {formatDateJSX(config.info.lastUpdatedTime)} AGO</div>
|
|
139
|
-
{config.parameters.rollingWindow && <div>Rolling window: {formatTime(config.parameters.rollingWindow)}</div> || undefined}
|
|
139
|
+
{config.parameters.rollingWindow && <div className={css.colorhsl(0, 50, 50).fontSize(14).fontWeight("bold")}>Rolling window: {formatTime(config.parameters.rollingWindow)}</div> || undefined}
|
|
140
140
|
</div>
|
|
141
141
|
</div>
|
|
142
142
|
</Anchor>
|
|
@@ -265,6 +265,45 @@ done`);
|
|
|
265
265
|
})();
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
+
export async function getRollingServiceInfo(config: {
|
|
269
|
+
serviceKey: string;
|
|
270
|
+
}): Promise<{ rollingScreenName: string; originalScreenName: string; expiresAt: number }[]> {
|
|
271
|
+
let rollingInfo: { rollingScreenName: string; originalScreenName: string; expiresAt: number }[] = [];
|
|
272
|
+
|
|
273
|
+
for (let [screenName, rolling] of rollingKeepScreenAlive) {
|
|
274
|
+
if (screenName.startsWith(config.serviceKey + "-")) {
|
|
275
|
+
rollingInfo.push({
|
|
276
|
+
rollingScreenName: rolling.rollingScreenName,
|
|
277
|
+
originalScreenName: rolling.originalScreenName,
|
|
278
|
+
expiresAt: rolling.pinnedTime + rolling.pinnedDuration,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return rollingInfo;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export async function killRollingServicesForService(config: {
|
|
287
|
+
serviceKey: string;
|
|
288
|
+
}): Promise<void> {
|
|
289
|
+
let toDelete: string[] = [];
|
|
290
|
+
|
|
291
|
+
for (let [screenName, rolling] of rollingKeepScreenAlive) {
|
|
292
|
+
if (screenName.startsWith(config.serviceKey + "-")) {
|
|
293
|
+
console.log(red(`Explicitly killing rolling screen ${rolling.rollingScreenName} for service ${config.serviceKey}`));
|
|
294
|
+
await killScreen({
|
|
295
|
+
screenName: rolling.rollingScreenName,
|
|
296
|
+
});
|
|
297
|
+
rollingScreens.delete(rolling.rollingScreenName);
|
|
298
|
+
toDelete.push(screenName);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
for (let screenName of toDelete) {
|
|
303
|
+
rollingKeepScreenAlive.delete(screenName);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
268
307
|
|
|
269
308
|
const getTmuxPrefix = lazy(() => {
|
|
270
309
|
if (os.platform() === "win32") {
|
|
@@ -734,6 +773,17 @@ const resyncServicesBase = runInSerial(measureWrap(async function resyncServices
|
|
|
734
773
|
continue;
|
|
735
774
|
}
|
|
736
775
|
}
|
|
776
|
+
|
|
777
|
+
let rollingInfo = rollingKeepScreenAlive.get(screenName);
|
|
778
|
+
if (rollingInfo) {
|
|
779
|
+
console.log(red(`Service ${screenName} was disabled, killing associated rolling screen ${rollingInfo.rollingScreenName}`));
|
|
780
|
+
await killScreen({
|
|
781
|
+
screenName: rollingInfo.rollingScreenName,
|
|
782
|
+
});
|
|
783
|
+
rollingScreens.delete(rollingInfo.rollingScreenName);
|
|
784
|
+
rollingKeepScreenAlive.delete(screenName);
|
|
785
|
+
}
|
|
786
|
+
|
|
737
787
|
await killScreen({
|
|
738
788
|
screenName,
|
|
739
789
|
});
|
|
@@ -5,7 +5,7 @@ import { requiresNetworkTrustHook } from "../-d-trust/NetworkTrust2";
|
|
|
5
5
|
import { timeInMinute } from "socket-function/src/misc";
|
|
6
6
|
import { assertIsManagementUser } from "../diagnostics/managementPages";
|
|
7
7
|
import { isNode } from "typesafecss";
|
|
8
|
-
import { streamScreenOutput } from "./machineApplyMainCode";
|
|
8
|
+
import { streamScreenOutput, getRollingServiceInfo, killRollingServicesForService } from "./machineApplyMainCode";
|
|
9
9
|
import { Querysub } from "../4-querysub/QuerysubController";
|
|
10
10
|
import { getPathStr2 } from "../path";
|
|
11
11
|
import { getGitURLLive, setGitRef } from "../4-deploy/git";
|
|
@@ -140,6 +140,18 @@ class MachineControllerBase {
|
|
|
140
140
|
await runPromise("bash machine-startup.sh", { cwd: os.homedir(), detach: true });
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
public async getRollingServiceInfo(config: {
|
|
144
|
+
serviceKey: string;
|
|
145
|
+
}): Promise<{ rollingScreenName: string; originalScreenName: string; expiresAt: number }[]> {
|
|
146
|
+
return await getRollingServiceInfo(config);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
public async killRollingServices(config: {
|
|
150
|
+
serviceKey: string;
|
|
151
|
+
}): Promise<void> {
|
|
152
|
+
await killRollingServicesForService(config);
|
|
153
|
+
}
|
|
154
|
+
|
|
143
155
|
}
|
|
144
156
|
|
|
145
157
|
let forwardedCallbacks = new Map<string, string>();
|
|
@@ -152,6 +164,8 @@ export const MachineController = getSyncedController(SocketFunction.register(
|
|
|
152
164
|
watchOtherScreenOutput: {},
|
|
153
165
|
deployMachineFromBrowser: {},
|
|
154
166
|
deployMachine: {},
|
|
167
|
+
getRollingServiceInfo: {},
|
|
168
|
+
killRollingServices: {},
|
|
155
169
|
}),
|
|
156
170
|
() => ({
|
|
157
171
|
hooks: [assertIsManagementUser],
|
|
@@ -33,7 +33,7 @@ export const SERVICE_NODE_FILE_NAME = "serviceNodeId.txt";
|
|
|
33
33
|
export type MachineInfo = {
|
|
34
34
|
machineId: string;
|
|
35
35
|
|
|
36
|
-
// Used to
|
|
36
|
+
// Used to talk to the apply script directly (ex, recheck the service config, kill the rolling nodes, etc)
|
|
37
37
|
applyNodeId: string;
|
|
38
38
|
|
|
39
39
|
heartbeat: number;
|
|
@@ -23,6 +23,7 @@ import { PUBLIC_MOVE_THRESHOLD } from "./BufferIndexLogsOptimizationConstants";
|
|
|
23
23
|
import { atomic } from "../../../2-proxy/PathValueProxyWatcher";
|
|
24
24
|
import { errorToUndefined } from "querysub/src/errors";
|
|
25
25
|
import { IndexedLogResults, createEmptyIndexedLogResults } from "./BufferIndexHelpers";
|
|
26
|
+
import { TimeFilePath } from "./TimeFileTree";
|
|
26
27
|
|
|
27
28
|
let searchText = new URLParam("searchText", "");
|
|
28
29
|
let readLiveData = new URLParam("readLiveData", false);
|
|
@@ -435,6 +436,19 @@ export class LogViewer3 extends qreact.Component {
|
|
|
435
436
|
this.state.paths = allPaths;
|
|
436
437
|
this.state.loadingPaths = false;
|
|
437
438
|
});
|
|
439
|
+
return allPaths;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
async updatePaths() {
|
|
443
|
+
let prevPaths = this.getPaths();
|
|
444
|
+
let newPaths = await this.loadPaths();
|
|
445
|
+
Querysub.commitLocal(() => {
|
|
446
|
+
function getHash(path: TimeFilePath): string {
|
|
447
|
+
return path.threadId + "_" + path.machineId;
|
|
448
|
+
}
|
|
449
|
+
let keep = new Set(prevPaths.map(getHash));
|
|
450
|
+
this.state.paths = newPaths?.filter(x => keep.has(getHash(x))) || [];
|
|
451
|
+
});
|
|
438
452
|
}
|
|
439
453
|
|
|
440
454
|
cancel = async () => {
|
|
@@ -798,11 +812,16 @@ export class LogViewer3 extends qreact.Component {
|
|
|
798
812
|
<Button
|
|
799
813
|
flavor="large"
|
|
800
814
|
onClick={() => void this.loadPaths()}
|
|
801
|
-
hue={120}
|
|
815
|
+
hue={this.state.paths.length ? 200 : 120}
|
|
802
816
|
>
|
|
803
|
-
Preview Files
|
|
817
|
+
{this.state.paths.length && "Reset Files" || "Preview Files"}
|
|
804
818
|
</Button>
|
|
805
819
|
)}
|
|
820
|
+
{this.state.paths && !savedPathsURL.value &&
|
|
821
|
+
<Button flavor="large" hue={120} onClick={() => void this.updatePaths()}>
|
|
822
|
+
Update Files
|
|
823
|
+
</Button>
|
|
824
|
+
}
|
|
806
825
|
{savedPathsURL.value && (
|
|
807
826
|
<Button
|
|
808
827
|
flavor="large"
|
|
@@ -19,8 +19,13 @@ IMPORTANT! Now I am properly calling shutdown, so none of the streamed logs shou
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
BUG: Fix it so we properly kill rolling screens when we disable a service
|
|
23
23
|
|
|
24
|
+
TODO: Show rolling services somewhere
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
BUG: Why are CYOA deploys not working!
|
|
28
|
+
I even disabled it, and nothing. It's still running. WTF...
|
|
24
29
|
|
|
25
30
|
Hmm... why are not enough logs appearing?
|
|
26
31
|
- We only have logs for server.ts? Wtf?
|
|
@@ -35,7 +40,7 @@ Hmm... why are not enough logs appearing?
|
|
|
35
40
|
- Basically, just changes the code we're reading from multiple servers to select public servers instead, and then, of course, skip ourselves.
|
|
36
41
|
|
|
37
42
|
BUG: UGH... live logs for the remote server isn't working...
|
|
38
|
-
|
|
43
|
+
new non-local WATCH
|
|
39
44
|
- UGH... it being pending logs is annoying, as that's hard to debug locally...
|
|
40
45
|
AH! Why do we have so few logs?
|
|
41
46
|
|