querysub 0.450.0 → 0.451.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.450.0",
3
+ "version": "0.451.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",
@@ -19,13 +19,15 @@ import { safeLoop } from "socket-function/src/batching";
19
19
  import { errorToUndefined } from "../errors";
20
20
  import { shutdown } from "../diagnostics/periodic";
21
21
 
22
- export const archives = lazy(() => wrapArchivesWithCache(getArchives("path-values/")));
22
+ // Kept separate from the cache-wrapped `archives` so we can probe the underlying archives
23
+ // directly (without the cache layer in the way) when diagnosing missing-file failures.
24
+ const archivesBase = lazy(() => getArchives("path-values/"));
25
+ export const archives = lazy(() => wrapArchivesWithCache(archivesBase()));
23
26
  export const archivesLocks = lazy(() => getArchives("path-values-locks/"));
24
27
  export const archivesRecycleBin = lazy(() => wrapArchivesWithCache(getArchives("path-values-recycle-bin/")));
25
28
 
26
- // Backblaze's getInfo (listFileNames) can transiently report a just-written file as missing.
27
- // Before treating a missing file as a fatal "written too slowly" condition, recheck a few
28
- // times to confirm it really is gone.
29
+ // If getInfo reports a just-written file as missing, recheck a few times before treating it
30
+ // as a fatal "written too slowly" condition.
29
31
  const ARCHIVE_INFO_RECHECK_ATTEMPTS = 5;
30
32
  const ARCHIVE_INFO_RECHECK_DELAY = 5000;
31
33
 
@@ -224,14 +226,33 @@ export class PathValueArchives {
224
226
  let fileInfo = await archives().getInfo(fullPath);
225
227
  // NOTE: If no fileInfo... then our file was merged? Which... is BAD, as it means we took
226
228
  // too long to read it, so we probably took too long to write it too!
227
- // Backblaze's getInfo can transiently report a just-written file as missing, so recheck
228
- // a few times before treating a missing file as fatal.
229
229
  for (let attempt = 0; !fileInfo && attempt < ARCHIVE_INFO_RECHECK_ATTEMPTS; attempt++) {
230
230
  await delay(ARCHIVE_INFO_RECHECK_DELAY);
231
231
  fileInfo = await archives().getInfo(fullPath);
232
232
  }
233
233
  if (!fileInfo || fileInfo.writeTime > slowestFileWriteTime) {
234
- console.error(red(`File ${fullPath} was written too slowly, ${fileInfo?.writeTime || "undefined"} < ${slowestFileWriteTime}. This means some values will be rejected by reads. Killing server, our state is irrecoverable. Our watches have invalid data, and we have to stop before we create more invalid dependencies.`));
234
+ // If we're crashing because getInfo reports the file as missing, probe the
235
+ // underlying (non-cached) archives -- both getInfo and an actual get() of the
236
+ // bytes -- and record the results in the crash log, so we can tell whether that
237
+ // info is consistent. We do NOT use this as a fallback; we still crash.
238
+ let missingDiagnostic = "";
239
+ if (!fileInfo) {
240
+ let baseInfoStr: string;
241
+ try {
242
+ baseInfoStr = JSON.stringify(await archivesBase().getInfo(fullPath)) ?? "undefined";
243
+ } catch (e) {
244
+ baseInfoStr = `threw ${(e as Error).stack ?? e}`;
245
+ }
246
+ let baseGetStr: string;
247
+ try {
248
+ let baseData = await archivesBase().get(fullPath);
249
+ baseGetStr = baseData ? `${baseData.byteLength}B` : "undefined";
250
+ } catch (e) {
251
+ baseGetStr = `threw ${(e as Error).stack ?? e}`;
252
+ }
253
+ missingDiagnostic = ` [underlying archives probe: getInfo=${baseInfoStr}, get=${baseGetStr}, expected ${data.byteLength}B]`;
254
+ }
255
+ console.error(red(`File ${fullPath} was written too slowly, ${fileInfo?.writeTime || "undefined"} < ${slowestFileWriteTime}.${missingDiagnostic} This means some values will be rejected by reads. Killing server, our state is irrecoverable. Our watches have invalid data, and we have to stop before we create more invalid dependencies.`));
235
256
  await delay(5000);
236
257
  try {
237
258
  await shutdown();
@@ -40,6 +40,7 @@ let pages: {
40
40
  componentName: string;
41
41
  title: string;
42
42
  }[] = [];
43
+ let headerNotifications: preact.ComponentClass[] = [];
43
44
 
44
45
  let __schema: SchemaObject<unknown, {
45
46
  isManagementUser: () => boolean;
@@ -63,6 +64,9 @@ export async function registerManagementPages2(config: {
63
64
  controllerName?: string;
64
65
  getModule: () => Promise<any>;
65
66
 
67
+ // If provided, this component (exported from getModule) is rendered in the management header.
68
+ notificationComponentName?: string;
69
+
66
70
  title?: string;
67
71
  }[];
68
72
  }) {
@@ -240,6 +244,9 @@ export async function registerManagementPages2(config: {
240
244
  componentName: page.componentName,
241
245
  componentClass: createLazyComponent(page.getModule)(page.componentName),
242
246
  });
247
+ if (page.notificationComponentName) {
248
+ headerNotifications.push(createLazyComponent(page.getModule)(page.notificationComponentName));
249
+ }
243
250
  }
244
251
  }
245
252
  }
@@ -355,6 +362,7 @@ class ManagementRoot extends qreact.Component {
355
362
  </style>
356
363
  <div class={css.fillWidth.hbox(20, 4).wrap.hsl(245, 25, 80).pad2(20, 4).pointerEvents("all")}>
357
364
  <ErrorWarning />
365
+ {headerNotifications.map(N => <N />)}
358
366
  <ATag values={[
359
367
  managementPageURL.getOverride("MachinesPage"),
360
368
  currentViewParam.getOverride("services"),