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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "querysub",
3
- "version": "0.693.0",
3
+ "version": "0.695.0",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "note1": "note on node-forge fork, see https://github.com/digitalbazaar/forge/issues/744 for details",
@@ -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 sampleCount = Math.min(prev?.sampleCount || 0, LATENCY_SAMPLE_LIMIT);
75
+ let pingCount = prev?.sampleCount || 0;
74
76
  let history = prev?.history || [];
75
- history.push(latency);
76
- if (history.length > LATENCY_HISTORY_LIMIT) {
77
- history.shift();
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: ((prev?.averageLatency || 0) * sampleCount + latency) / (sampleCount + 1),
81
- sampleCount: sampleCount + 1,
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(8).button.relative
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"))