sliftutils 1.7.40 → 1.7.42

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.
Files changed (45) hide show
  1. package/index.d.ts +2 -0
  2. package/misc/dist/environment.ts.cache +2 -2
  3. package/misc/dist/getSecret.ts.cache +2 -2
  4. package/misc/dist/strings.ts.cache +2 -2
  5. package/misc/dist/zip.ts.cache +2 -2
  6. package/misc/https/dist/certs.ts.cache +2 -2
  7. package/misc/https/dist/persistentLocalStorage.ts.cache +2 -2
  8. package/package.json +1 -1
  9. package/render-utils/dist/observer.tsx.cache +2 -2
  10. package/storage/BulkDatabase2/dist/BulkDatabaseBase.ts.cache +2 -2
  11. package/storage/BulkDatabase2/dist/BulkDatabaseFormat.ts.cache +2 -2
  12. package/storage/BulkDatabase2/dist/BulkDatabaseMerge.ts.cache +2 -2
  13. package/storage/BulkDatabase2/dist/BulkDatabaseReader.ts.cache +2 -2
  14. package/storage/BulkDatabase2/dist/LoadedIndex.ts.cache +2 -2
  15. package/storage/BulkDatabase2/dist/WriteOverlay.ts.cache +2 -2
  16. package/storage/BulkDatabase2/dist/blockCache.ts.cache +2 -2
  17. package/storage/BulkDatabase2/dist/mergeLock.ts.cache +2 -2
  18. package/storage/BulkDatabase2/dist/mergeMarkers.ts.cache +2 -2
  19. package/storage/BulkDatabase2/dist/streamLog.ts.cache +2 -2
  20. package/storage/BulkDatabase2/dist/syncClient.ts.cache +2 -2
  21. package/storage/dist/ArchivesDisk.ts.cache +2 -2
  22. package/storage/dist/FileFolderAPI.tsx.cache +2 -2
  23. package/storage/dist/IArchives.ts.cache +2 -2
  24. package/storage/dist/IndexedDBFileFolderAPI.ts.cache +2 -2
  25. package/storage/dist/JSONStorage.ts.cache +2 -2
  26. package/storage/dist/PendingManager.tsx.cache +2 -2
  27. package/storage/dist/TransactionStorage.ts.cache +2 -2
  28. package/storage/dist/backblaze.ts.cache +2 -2
  29. package/storage/dist/fileSystemPointer.ts.cache +2 -2
  30. package/storage/dist/remoteFileStorage.ts.cache +2 -2
  31. package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +2 -2
  32. package/storage/remoteStorage/dist/ArchivesUrl.ts.cache +2 -2
  33. package/storage/remoteStorage/dist/blobStore.ts.cache +2 -2
  34. package/storage/remoteStorage/dist/cliArgs.ts.cache +2 -2
  35. package/storage/remoteStorage/dist/createArchives.ts.cache +2 -2
  36. package/storage/remoteStorage/dist/deployTakeover.ts.cache +2 -2
  37. package/storage/remoteStorage/dist/intermediateSources.ts.cache +2 -2
  38. package/storage/remoteStorage/dist/remoteConfig.ts.cache +2 -2
  39. package/storage/remoteStorage/dist/sourceWrapper.ts.cache +17 -4
  40. package/storage/remoteStorage/dist/storageClientController.ts.cache +2 -2
  41. package/storage/remoteStorage/dist/storageController.ts.cache +2 -2
  42. package/storage/remoteStorage/dist/storageServerState.ts.cache +9 -36
  43. package/storage/remoteStorage/sourceWrapper.d.ts +2 -0
  44. package/storage/remoteStorage/sourceWrapper.ts +14 -2
  45. package/storage/remoteStorage/storageServerState.ts +5 -31
@@ -21,6 +21,8 @@ export declare class SourceWrapper {
21
21
  }): Promise<SourceWrapper>;
22
22
  getDebugName(): string;
23
23
  isConnected(): boolean;
24
+ /** A source whose window has passed is never read from or written to (see the window checks in ArchivesChain), and an intermediate only exists for the minutes of a deploy switchover - on either, being unreachable is expected, not a problem to report. */
25
+ private isConnectionProblemWorthReporting;
24
26
  /** Call after a request failed while isConnected() was false: starts (if not already running) the background reconnect loop. Never blocks - the failed request still throws. */
25
27
  noteFailure(): void;
26
28
  private reconnectLoop;
@@ -101,11 +101,19 @@ export class SourceWrapper {
101
101
  return this.remote.isConnected();
102
102
  }
103
103
 
104
+ /** A source whose window has passed is never read from or written to (see the window checks in ArchivesChain), and an intermediate only exists for the minutes of a deploy switchover - on either, being unreachable is expected, not a problem to report. */
105
+ private isConnectionProblemWorthReporting(): boolean {
106
+ if (this.config.intermediate) return false;
107
+ return this.config.validWindow[1] > Date.now();
108
+ }
109
+
104
110
  /** Call after a request failed while isConnected() was false: starts (if not already running) the background reconnect loop. Never blocks - the failed request still throws. */
105
111
  public noteFailure(): void {
106
112
  if (!this.background || this.disposed || this.reconnectRunning) return;
107
113
  if (this.isConnected()) return;
108
- console.error(`Cannot connect to storage ${this.getDebugName()}`);
114
+ if (this.isConnectionProblemWorthReporting()) {
115
+ console.error(`Cannot connect to storage ${this.getDebugName()}`);
116
+ }
109
117
  this.reconnectRunning = true;
110
118
  void this.reconnectLoop();
111
119
  }
@@ -126,7 +134,9 @@ export class SourceWrapper {
126
134
  } catch (e) {
127
135
  // Even a failing call (e.g. access denied) proves the connection is back
128
136
  if (this.isConnected()) break;
129
- console.warn(`Cannot connect to storage ${this.getDebugName()}, retrying in ${Math.round(retryDelay / 1000)}s. ${(e as Error).stack ?? e}`);
137
+ if (this.isConnectionProblemWorthReporting()) {
138
+ console.warn(`Cannot connect to storage ${this.getDebugName()}, retrying in ${Math.round(retryDelay / 1000)}s. ${(e as Error).stack ?? e}`);
139
+ }
130
140
  }
131
141
  retryDelay = Math.min(RETRY_MAX_DELAY, retryDelay * RETRY_GROWTH);
132
142
  }
@@ -182,6 +192,8 @@ export class SourceWrapper {
182
192
  public startPinging(): void {
183
193
  const remote = this.remote;
184
194
  if (!remote || this.pingTimer || this.disposed) return;
195
+ // Latency only decides which shard a variable-shard write materializes into, and a source whose window has passed never receives writes - so measuring it is pointless traffic
196
+ if (this.config.validWindow[1] <= Date.now()) return;
185
197
  let measure = async () => {
186
198
  let start = Date.now();
187
199
  try {
@@ -756,40 +756,14 @@ async function propagateRoutingConfig(loaded: LoadedBucket, next: RemoteConfig,
756
756
  }
757
757
  }
758
758
 
759
- /** Every bucket that exists on this server's disk, as account/bucketName keys. */
760
- async function getAllBucketKeys(): Promise<string[]> {
761
- let root = path.join(getStorageServerConfig().folder, "buckets2");
762
- let accounts: string[];
763
- try {
764
- accounts = await fs.promises.readdir(root);
765
- } catch {
766
- return [];
767
- }
768
- let keys: string[] = [];
769
- for (let account of accounts) {
770
- let names: string[];
771
- try {
772
- names = await fs.promises.readdir(path.join(root, account));
773
- } catch {
774
- continue;
775
- }
776
- for (let bucketName of names) {
777
- keys.push(`${account}/${bucketName}`);
778
- }
779
- }
780
- return keys;
781
- }
782
-
783
759
  async function maintainIntermediates(): Promise<void> {
784
760
  let { domain, port } = getStorageServerConfig();
785
761
  let takeover = getTakeoverIntermediate();
786
- // Every bucket on disk, not just the ones already in memory: a successor starts with nothing loaded, and a bucket whose config we never touch would keep sending its writes to the process that is about to die.
787
- for (let key of await getAllBucketKeys()) {
788
- let slash = key.indexOf("/");
789
- let loaded = await getLoadedBucket(key.slice(0, slash), key.slice(slash + 1)).catch((e: Error) => {
790
- console.error(`Loading bucket ${key} to maintain its switchover windows failed: ${e.stack ?? e}`);
791
- return undefined;
792
- });
762
+ // ONLY buckets already in memory. A switchover must never load a bucket: loading starts its synchronization, and buckets nothing has touched (legacy ones especially) have no writes to hand off in the first place. One that does get used mid-switchover loads on that access, and the next pass gives it its window.
763
+ for (let key of [...buckets.keys()]) {
764
+ let loadedPromise = buckets.get(key);
765
+ if (!loadedPromise) continue;
766
+ let loaded = await loadedPromise.catch(() => undefined);
793
767
  if (!loaded) continue;
794
768
  let expired = expireIntermediateSources(loaded.routing, Date.now());
795
769
  if (JSON.stringify(expired) !== JSON.stringify(loaded.routing)) {