querysub 0.693.0 → 0.695.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
CHANGED
|
@@ -27,6 +27,8 @@ const LATENCY_SAMPLE_LIMIT = 20;
|
|
|
27
27
|
const LATENCY_HISTORY_LIMIT = 100;
|
|
28
28
|
// Forget nodes we haven't been able to reach for this long.
|
|
29
29
|
const NODE_EXPIRY_TIME = LATENCY_POLL_INTERVAL * 5;
|
|
30
|
+
// Each of the first pings to a node replaces the history instead of adding to it, so only the last of them survives into the real history.
|
|
31
|
+
const LATENCY_WARMUP_PINGS = 3;
|
|
30
32
|
|
|
31
33
|
export type NodeLatencyInfo = {
|
|
32
34
|
averageLatency: number;
|
|
@@ -70,15 +72,19 @@ export function getOwnLatencies(): { [nodeId: string]: number } {
|
|
|
70
72
|
|
|
71
73
|
function recordLatency(nodeId: string, latency: number) {
|
|
72
74
|
let prev = latencyByNode.get(nodeId);
|
|
73
|
-
let
|
|
75
|
+
let pingCount = prev?.sampleCount || 0;
|
|
74
76
|
let history = prev?.history || [];
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
77
|
+
if (pingCount < LATENCY_WARMUP_PINGS) {
|
|
78
|
+
history = [latency];
|
|
79
|
+
} else {
|
|
80
|
+
history.push(latency);
|
|
81
|
+
if (history.length > LATENCY_HISTORY_LIMIT) {
|
|
82
|
+
history.shift();
|
|
83
|
+
}
|
|
78
84
|
}
|
|
79
85
|
latencyByNode.set(nodeId, {
|
|
80
|
-
averageLatency: ((
|
|
81
|
-
sampleCount:
|
|
86
|
+
averageLatency: history.reduce((sum, x) => sum + x, 0) / history.length,
|
|
87
|
+
sampleCount: pingCount + 1,
|
|
82
88
|
lastSeen: Date.now(),
|
|
83
89
|
history,
|
|
84
90
|
});
|
|
@@ -1075,6 +1075,11 @@ export class Querysub {
|
|
|
1075
1075
|
if (isClient()) {
|
|
1076
1076
|
throw new Error(`--client processes cannot host a service. Either stop passing --client and keep the process on the network and trusted, or stop calling hostServer and call Querysub.configRootDiscoveryLocation instead. You MUST provide configRootDiscoveryLocation a valid nodeId. Which means either you do server selection manually, or if you are developing, just point it to "127-0-0-1.${getDomain()}:your local port here"`);
|
|
1077
1077
|
}
|
|
1078
|
+
// Hot reloading on public servers breaks things when we update (as the git pull triggers a hot reload), so... don't do that.
|
|
1079
|
+
if (!isPublic() || yargObj.hot) {
|
|
1080
|
+
watchFilesAndTriggerHotReloading();
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1078
1083
|
await getIdentityCAPromise(getDomain());
|
|
1079
1084
|
let times: {
|
|
1080
1085
|
name: string;
|
|
@@ -595,19 +595,6 @@ export class ServiceDetailPage extends qreact.Component {
|
|
|
595
595
|
Old instances shut down in {formatTime(scheduledDeploy.switchTime + scheduledDeploy.overlapTime - now)} ({formatDateTimeDetailed(scheduledDeploy.switchTime + scheduledDeploy.overlapTime)})
|
|
596
596
|
</div>
|
|
597
597
|
<div className={css.hbox(8)}>
|
|
598
|
-
<button
|
|
599
|
-
className={css.pad2(12, 8).button.bord2(0, 0, 20).hsl(0, 70, 90)}
|
|
600
|
-
onClick={() => {
|
|
601
|
-
this.runControllerAction(async () => {
|
|
602
|
-
let cancelled = await controller.cancelScheduledDeploy.promise(selectedServiceId);
|
|
603
|
-
// Keep the cancelled changes in the editor, so they aren't lost (Discard Changes drops them)
|
|
604
|
-
Querysub.commit(() => {
|
|
605
|
-
this.state.editorState = cancelled;
|
|
606
|
-
});
|
|
607
|
-
});
|
|
608
|
-
}}>
|
|
609
|
-
Cancel Scheduled Deploy
|
|
610
|
-
</button>
|
|
611
598
|
<button
|
|
612
599
|
className={css.pad2(12, 8).button.bord2(45, 80, 35).hsl(45, 85, 82)}
|
|
613
600
|
disabled={this.state.isDeploying}
|
|
@@ -415,20 +415,6 @@ export class MachineServiceControllerBase {
|
|
|
415
415
|
void this.notifyMachines([], getConfigMachineIds(normalizeServiceConfig(serviceConfig)));
|
|
416
416
|
}
|
|
417
417
|
|
|
418
|
-
/** Cancels parameters that are scheduled to deploy (releaseTime in the future), reverting to what is currently live. Returns the cancelled config, so the caller can keep the edits (ex, back in the editor). */
|
|
419
|
-
public async cancelScheduledDeploy(serviceId: string): Promise<ServiceConfig> {
|
|
420
|
-
let record = await serviceConfigs.get(serviceId);
|
|
421
|
-
if (!record) {
|
|
422
|
-
throw new Error(`Service ${serviceId} does not exist`);
|
|
423
|
-
}
|
|
424
|
-
normalizeServiceConfig(record);
|
|
425
|
-
if (!record.parameters.releaseTime || Date.now() >= record.parameters.releaseTime || !record.oldParameters) {
|
|
426
|
-
throw new Error(`Service ${serviceId} has no scheduled deploy to cancel (it may have already gone live)`);
|
|
427
|
-
}
|
|
428
|
-
await serviceConfigs.set(serviceId, { ...record, parameters: record.oldParameters, oldParameters: undefined });
|
|
429
|
-
void this.notifyMachines(getConfigMachineIds(record), []);
|
|
430
|
-
return stripReleaseState(record);
|
|
431
|
-
}
|
|
432
418
|
public async getServiceConfigType(): Promise<string> {
|
|
433
419
|
return extractType(module, "ServiceConfig");
|
|
434
420
|
}
|
|
@@ -657,7 +643,6 @@ export const MachineServiceController = getSyncedController(
|
|
|
657
643
|
setMachineConfig: {},
|
|
658
644
|
addServiceConfig: {},
|
|
659
645
|
setServiceConfigs: {},
|
|
660
|
-
cancelScheduledDeploy: {},
|
|
661
646
|
getServiceConfigType: {},
|
|
662
647
|
deleteServiceConfig: {},
|
|
663
648
|
getGitInfo: {},
|
|
@@ -682,7 +667,6 @@ export const MachineServiceController = getSyncedController(
|
|
|
682
667
|
setMachineConfig: ["MachineConfig", "MachineConfigList"],
|
|
683
668
|
addServiceConfig: ["ServiceConfig", "ServiceConfigList"],
|
|
684
669
|
setServiceConfigs: ["ServiceConfig"],
|
|
685
|
-
cancelScheduledDeploy: ["ServiceConfig"],
|
|
686
670
|
deleteServiceConfig: ["ServiceConfig", "ServiceConfigList"],
|
|
687
671
|
commitPushService: ["gitInfo", "ServiceConfig"],
|
|
688
672
|
commitPushAndPublishQuerysub: ["gitInfo", "ServiceConfig"],
|
|
@@ -30,6 +30,11 @@ export type InputLabelProps = Omit<InputProps, "label" | "title"> & {
|
|
|
30
30
|
fillWidth?: boolean | number;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
+
// A checkbox is a small square that reads as belonging to the words beside it, so it sits tight against
|
|
34
|
+
// its label; every other input is a box of its own and wants room between the two.
|
|
35
|
+
const LABEL_GAP = 8;
|
|
36
|
+
const CHECKBOX_LABEL_GAP = 2;
|
|
37
|
+
|
|
33
38
|
function roundToDecimals(value: number, decimals: number) {
|
|
34
39
|
return Math.round(value * 10 ** decimals) / 10 ** decimals;
|
|
35
40
|
}
|
|
@@ -148,7 +153,7 @@ export class InputLabel extends qreact.Component<InputLabelProps> {
|
|
|
148
153
|
}
|
|
149
154
|
return (
|
|
150
155
|
<label onClick={onClick} class={
|
|
151
|
-
css.hbox(
|
|
156
|
+
css.hbox(props.checkbox ? CHECKBOX_LABEL_GAP : LABEL_GAP).button.relative
|
|
152
157
|
+ " trigger-hover "
|
|
153
158
|
+ props.outerClass
|
|
154
159
|
+ (props.flavor === "large" && css.fontSize(18, "soft"))
|