querysub 0.654.0 → 0.655.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.654.0",
3
+ "version": "0.655.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",
@@ -1,6 +1,6 @@
1
1
  import { SocketFunction } from "socket-function/SocketFunction";
2
2
  import { qreact } from "../../4-dom/qreact";
3
- import { MACHINE_RESYNC_INTERVAL, MachineServiceController, ServiceConfig, getMachineIdList } from "../machineSchema";
3
+ import { MACHINE_RESYNC_INTERVAL, MachineServiceController, ServiceConfig, getMachineIdList, getMachineInfoLive } from "../machineSchema";
4
4
  import { css } from "typesafecss";
5
5
  import { currentViewParam, selectedMachineIdParam, selectedServiceIdParam } from "../urlParams";
6
6
  import { formatNumber, formatVeryNiceDateTime } from "socket-function/src/formatting/format";
@@ -19,7 +19,7 @@ export class MachineDetailPage extends qreact.Component {
19
19
  if (!selectedMachineId) return <div>No machine selected</div>;
20
20
 
21
21
  let controller = MachineServiceController(SocketFunction.browserNodeId());
22
- let machineInfo = controller.getMachineInfo(selectedMachineId);
22
+ let machineInfo = getMachineInfoLive(selectedMachineId);
23
23
  let serviceList = controller.getServiceList();
24
24
  let machineConfig = controller.getMachineConfig(selectedMachineId);
25
25
 
@@ -6,7 +6,7 @@ import { isDefined } from "../../misc";
6
6
  import { formatTime } from "socket-function/src/formatting/format";
7
7
  import { css } from "typesafecss";
8
8
  import { Querysub } from "../../4-querysub/Querysub";
9
- import { MachineServiceController, getLiveServiceParameters, getMachineTargets, applyCommandTemplate } from "../machineSchema";
9
+ import { MachineServiceController, getLiveServiceParameters, getMachineTargets, applyCommandTemplate, getMachineInfoLive } from "../machineSchema";
10
10
  import { FUNCTION_RUNNER_COMMAND_PREFIX } from "../serviceCategories";
11
11
 
12
12
  module.hotreload = true;
@@ -53,7 +53,7 @@ export class MachinePicker extends qreact.Component<{
53
53
  }> {
54
54
  render() {
55
55
  let controller = MachineServiceController(SocketFunction.browserNodeId());
56
- let machines = (controller.getMachineList() || []).map(x => controller.getMachineInfo(x)).filter(isDefined);
56
+ let machines = (controller.getMachineList() || []).map(x => getMachineInfoLive(x)).filter(isDefined);
57
57
  sort(machines, x => -x.heartbeat);
58
58
 
59
59
  let networksPerMachine = getMachineNetworks(controller);
@@ -1,6 +1,6 @@
1
1
  import { SocketFunction } from "socket-function/SocketFunction";
2
2
  import { qreact } from "../../4-dom/qreact";
3
- import { MACHINE_RESYNC_INTERVAL, MachineServiceController } from "../machineSchema";
3
+ import { MACHINE_RESYNC_INTERVAL, MachineServiceController, getMachineInfoLive } from "../machineSchema";
4
4
  import { css } from "typesafecss";
5
5
  import { t } from "../../2-proxy/schema2";
6
6
  import { Querysub } from "../../4-querysub/Querysub";
@@ -26,7 +26,7 @@ export class MachinesListPage extends qreact.Component {
26
26
 
27
27
  if (!machineList) return <div>Loading machines...</div>;
28
28
 
29
- let machines = machineList.map(machineId => [machineId, controller.getMachineInfo(machineId)] as const).filter(x => x[1]);
29
+ let machines = machineList.map(machineId => [machineId, getMachineInfoLive(machineId)] as const).filter(x => x[1]);
30
30
  sort(machines, x => -(x[1]?.heartbeat || 0));
31
31
 
32
32
  let machineConfigs = controller.getMachineConfigList();
@@ -1,6 +1,6 @@
1
1
  import { SocketFunction } from "socket-function/SocketFunction";
2
2
  import { qreact } from "../../4-dom/qreact";
3
- import { DEFAULT_OVERLAP_TIME, MACHINE_RESYNC_INTERVAL, MachineServiceController, ServiceConfig, ServiceParameters, applyCommandTemplate, getCommandTemplateVariables, getLiveServiceParameters, getMachineTargets, setMachineTargets, stripReleaseState } from "../machineSchema";
3
+ import { DEFAULT_OVERLAP_TIME, MACHINE_RESYNC_INTERVAL, MachineServiceController, ServiceConfig, ServiceParameters, applyCommandTemplate, getCommandTemplateVariables, getLiveServiceParameters, getMachineInfoLive, getMachineTargets, setMachineTargets, stripReleaseState } from "../machineSchema";
4
4
  import { css } from "typesafecss";
5
5
  import { t } from "../../2-proxy/schema2";
6
6
  import { Querysub } from "../../4-querysub/Querysub";
@@ -121,7 +121,7 @@ export class ServiceDetailPage extends qreact.Component {
121
121
 
122
122
  return <div className={css.vbox(8).fillWidth}>
123
123
  {[...machineGroups.entries()].map(([machineId, group]) => {
124
- let ip = controller.getMachineInfo(machineId)?.info["getExternalIP"];
124
+ let ip = getMachineInfoLive(machineId)?.info["getExternalIP"];
125
125
  if (typeof ip !== "string") {
126
126
  ip = "";
127
127
  }
@@ -226,7 +226,7 @@ export class ServiceDetailPage extends qreact.Component {
226
226
  let machineStatuses = machineTargets.map(({ machineId, variables }) => {
227
227
  let index = nextIndexes.get(machineId) || 0;
228
228
  nextIndexes.set(machineId, index + 1);
229
- let machineInfo = controller.getMachineInfo(machineId);
229
+ let machineInfo = getMachineInfoLive(machineId);
230
230
  let machineConfig = controller.getMachineConfig(machineId);
231
231
  const serviceInfo = machineInfo?.services[selectedServiceId || ""];
232
232
  const isMachineDead = machineInfo ? Date.now() - machineInfo.heartbeat > (MACHINE_RESYNC_INTERVAL * 4) : true;
@@ -248,7 +248,7 @@ export class ServiceDetailPage extends qreact.Component {
248
248
  sort(machineStatuses, x => (x.isDisabled ? 3 : x.hasError ? 0 : x.isMachineDead ? 1 : 2) * 1000000 + x.heartbeat);
249
249
  let now = Querysub.nowDelayed(timeInSecond);
250
250
 
251
- let machines = (controller.getMachineList() || []).map(x => controller.getMachineInfo(x)).filter(isDefined);
251
+ let machines = (controller.getMachineList() || []).map(x => getMachineInfoLive(x)).filter(isDefined);
252
252
  sort(machines, x => -x.heartbeat);
253
253
 
254
254
  return <div className={css.vbox(16).fillWidth}>
@@ -1,6 +1,6 @@
1
1
  import { SocketFunction } from "socket-function/SocketFunction";
2
2
  import { qreact } from "../../4-dom/qreact";
3
- import { DEFAULT_OVERLAP_TIME, MachineServiceController, ServiceConfig, getLiveServiceParameters, getMachineIdList } from "../machineSchema";
3
+ import { DEFAULT_OVERLAP_TIME, MachineServiceController, ServiceConfig, getLiveServiceParameters, getMachineIdList, getMachineInfoLive } from "../machineSchema";
4
4
  import { css } from "typesafecss";
5
5
  import { t } from "../../2-proxy/schema2";
6
6
  import { Querysub } from "../../4-querysub/Querysub";
@@ -62,7 +62,7 @@ export class ServicesListPage extends qreact.Component {
62
62
  let services = serviceList.map(serviceId => [serviceId, controller.getServiceConfig(serviceId)] as const);
63
63
  sort(services, x => -(x[1]?.info.lastUpdatedTime || Date.now()) - (x[1]?.parameters.deploy && (Number.MAX_SAFE_INTEGER / 2) || 0));
64
64
 
65
- let getMachineInfo = cache((machineId: string) => controller.getMachineInfo(machineId));
65
+ let getMachineInfo = cache((machineId: string) => getMachineInfoLive(machineId));
66
66
  let getMachineConfig = cache((machineId: string) => controller.getMachineConfig(machineId));
67
67
 
68
68
  let keyCounts = new Map<string, number>();
@@ -9,7 +9,7 @@ import { getSyncedController } from "../library-components/SyncedController";
9
9
  import { requiresNetworkTrustHook } from "../-d-trust/NetworkTrust2";
10
10
  import { extractType } from "../misc/extractType";
11
11
  import { getOwnMachineId } from "sliftutils/misc/https/certs";
12
- import { delay, runInSerial, runInfinitePollCallAtStart } from "socket-function/src/batching";
12
+ import { delay, runInSerial, runInfinitePoll, runInfinitePollCallAtStart } from "socket-function/src/batching";
13
13
  import { lazy } from "socket-function/src/caching";
14
14
  import { errorToUndefinedSilent } from "../errors";
15
15
  import { commitAndPush, getGitDiff, getGitRefInfo, getGitRefLive, getGitURLLive, getGitUncommitted, getLatestRefOnUpstreamBranch, setGitRef } from "../4-deploy/git";
@@ -704,3 +704,20 @@ export const MachineServiceController = getSyncedController(
704
704
  }
705
705
  }
706
706
  );
707
+
708
+ const MACHINE_INFO_REFRESH_INTERVAL = timeInMinute * 5;
709
+ let accessedMachineInfoIds = new Set<string>();
710
+ const startMachineInfoRefreshLoop = lazy(() => {
711
+ runInfinitePoll(MACHINE_INFO_REFRESH_INTERVAL, () => {
712
+ let controller = MachineServiceController(SocketFunction.browserNodeId());
713
+ for (let id of accessedMachineInfoIds) {
714
+ controller.getMachineInfo.refresh(id);
715
+ }
716
+ });
717
+ });
718
+ /** Machine infos only change via heartbeats, which nothing on the client invalidates, so a page left open shows an ever-older heartbeat and eventually flags a healthy machine as likely dead. All UI reads go through here: the first access starts a loop that keeps refreshing every machine that has ever been accessed (refreshes are cheap, and this way nothing polls unless the data was actually used). */
719
+ export function getMachineInfoLive(machineId: string): MachineInfo | undefined {
720
+ accessedMachineInfoIds.add(machineId);
721
+ startMachineInfoRefreshLoop();
722
+ return MachineServiceController(SocketFunction.browserNodeId()).getMachineInfo(machineId);
723
+ }