orez-sync-cf-host 0.4.71 → 0.5.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": "orez-sync-cf-host",
3
- "version": "0.4.71",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./src/index.ts"
Binary file
package/src/host.ts CHANGED
@@ -372,12 +372,20 @@ export function createSyncDurableObject<Env extends SyncHostEnv>(
372
372
  if (config.queryAware || config.resolveQuery)
373
373
  this.#wasm(() => engine_init_query_schema(this.#engineDb))
374
374
  })
375
- if (config.upstream && (await ctx.storage.getAlarm()) === null) {
376
- await ctx.storage.setAlarm(Date.now() + upstreamIntervalMs)
377
- }
378
375
  })
379
376
  }
380
377
 
378
+ #armUpstreamAlarm(): void {
379
+ if (!config.upstream) return
380
+ this.ctx.waitUntil(
381
+ (async () => {
382
+ if ((await this.ctx.storage.getAlarm()) === null) {
383
+ await this.ctx.storage.setAlarm(Date.now() + upstreamIntervalMs)
384
+ }
385
+ })()
386
+ )
387
+ }
388
+
381
389
  #wasm<T>(call: () => T): T {
382
390
  this.#counters.wasmBoundaryCalls++
383
391
  return call()
@@ -1328,6 +1336,12 @@ export function createSyncDurableObject<Env extends SyncHostEnv>(
1328
1336
  const [client, server] = Object.values(pair)
1329
1337
  server.serializeAttachment({ clientID } satisfies SocketAttachment)
1330
1338
  this.ctx.acceptWebSocket(server, [`client:${clientID}`])
1339
+ // The alarm is only a safety net for an actively connected consumer.
1340
+ // A namespace with no wake socket has nobody to notify; its next pull or
1341
+ // push ingests synchronously. Arming from construction made every
1342
+ // namespace poll upstream forever after its first request, even across
1343
+ // DO eviction, producing a permanent rows-written floor at zero traffic.
1344
+ this.#armUpstreamAlarm()
1331
1345
  return new Response(null, { status: 101, webSocket: client })
1332
1346
  }
1333
1347
 
@@ -1345,21 +1359,24 @@ export function createSyncDurableObject<Env extends SyncHostEnv>(
1345
1359
  }
1346
1360
  }
1347
1361
  ).memory
1348
- return json({
1349
- bootID: this.#bootID,
1350
- idleTeardownMs,
1351
- hibernations: this.#hibernations,
1352
- databaseSizeBytes: this.ctx.storage.sql.databaseSize,
1353
- connectedWakeSockets: this.ctx.getWebSockets().length,
1354
- writerEnabled: this.#writerEnabled(),
1355
- wasmMemoryBytes: engine_memory_bytes(),
1356
- heapUsedBytes: heap?.usedJSHeapSize ?? null,
1357
- heapTotalBytes: heap?.totalJSHeapSize ?? null,
1358
- heapLimitBytes: heap?.jsHeapSizeLimit ?? null,
1359
- engine: this.#engineState(),
1360
- counters: this.#counters,
1361
- ingestBreaker: this.#ingestBreaker.status(),
1362
- })
1362
+ return this.ctx.storage.getAlarm().then((upstreamAlarmAt) =>
1363
+ json({
1364
+ bootID: this.#bootID,
1365
+ idleTeardownMs,
1366
+ hibernations: this.#hibernations,
1367
+ databaseSizeBytes: this.ctx.storage.sql.databaseSize,
1368
+ connectedWakeSockets: this.ctx.getWebSockets().length,
1369
+ upstreamAlarmAt,
1370
+ writerEnabled: this.#writerEnabled(),
1371
+ wasmMemoryBytes: engine_memory_bytes(),
1372
+ heapUsedBytes: heap?.usedJSHeapSize ?? null,
1373
+ heapTotalBytes: heap?.totalJSHeapSize ?? null,
1374
+ heapLimitBytes: heap?.jsHeapSizeLimit ?? null,
1375
+ engine: this.#engineState(),
1376
+ counters: this.#counters,
1377
+ ingestBreaker: this.#ingestBreaker.status(),
1378
+ })
1379
+ )
1363
1380
  }
1364
1381
  if (route === '/admin/sql') {
1365
1382
  return request.json().then((body) => {
@@ -1524,6 +1541,7 @@ export function createSyncDurableObject<Env extends SyncHostEnv>(
1524
1541
  }
1525
1542
 
1526
1543
  async alarm(): Promise<void> {
1544
+ if (this.ctx.getWebSockets().length === 0) return
1527
1545
  try {
1528
1546
  await this.#ingest()
1529
1547
  } catch (error) {
@@ -1535,10 +1553,12 @@ export function createSyncDurableObject<Env extends SyncHostEnv>(
1535
1553
  })
1536
1554
  )
1537
1555
  } finally {
1538
- const retryAfterMs = this.#ingestBreaker.status().retryAfterMs
1539
- await this.ctx.storage.setAlarm(
1540
- Date.now() + Math.max(upstreamIntervalMs, retryAfterMs)
1541
- )
1556
+ if (this.ctx.getWebSockets().length > 0) {
1557
+ const retryAfterMs = this.#ingestBreaker.status().retryAfterMs
1558
+ await this.ctx.storage.setAlarm(
1559
+ Date.now() + Math.max(upstreamIntervalMs, retryAfterMs)
1560
+ )
1561
+ }
1542
1562
  }
1543
1563
  }
1544
1564
 
package/src/types.ts CHANGED
@@ -114,7 +114,7 @@ export type UpstreamConfig = {
114
114
  namespacePath: string | ((namespace: string) => string)
115
115
  /** Feed page size; the cursor loop continues until the reported head is reached. */
116
116
  changeLimit?: number
117
- /** Durable Object alarm safety net. Defaults to 15 seconds. */
117
+ /** Active wake-socket alarm safety net. Defaults to 15 seconds. */
118
118
  intervalMs?: number
119
119
  /** Billable SQLite rows written by ingest per rolling window. Defaults to 150,000. */
120
120
  ingestBudgetRows?: number