@bakery-framework/plugin-analytics 2.1.1 → 2.2.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": "@bakery-framework/plugin-analytics",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "description": "Bakery analytics plugin.",
5
5
  "keywords": [
6
6
  "bakery",
@@ -36,7 +36,7 @@
36
36
  "!src/tests"
37
37
  ],
38
38
  "dependencies": {
39
- "@bakery-framework/core": "^2.1.1"
39
+ "@bakery-framework/core": "^2.2.0"
40
40
  },
41
41
  "engines": {
42
42
  "bun": ">=1.4.0"
package/src/core.ts CHANGED
@@ -288,6 +288,7 @@ export function getLatestAnalyticsSnapshot() {
288
288
  uniqueRequests: 0,
289
289
  errorPageHits: 0,
290
290
  ping: 0,
291
+ activeSessions: 0,
291
292
  }
292
293
  )
293
294
  }
@@ -1,5 +1,4 @@
1
1
  import { Bakery } from '@bakery-framework/core/core/bakery'
2
- import { Session } from '@bakery-framework/core/session'
3
2
  import type { JsonResponseData } from '@bakery-framework/core/utils/common'
4
3
  import {
5
4
  type AuthorizeFn,
@@ -61,7 +60,9 @@ export function computeStats(
61
60
  platform: process.platform,
62
61
  arch: process.arch,
63
62
  activeLoggers: core.connectedLoggers.size,
64
- activeSessions: Session.count,
63
+ // The tick's count, at most a second old: this runs synchronously, and
64
+ // a configured store can only be counted asynchronously.
65
+ activeSessions: latestHistory.activeSessions,
65
66
  routeHits: latestHistory.routeHits,
66
67
  apiHits: latestHistory.apiHits || 0,
67
68
  pageHits: latestHistory.pageHits || 0,
package/src/loop.ts CHANGED
@@ -15,6 +15,13 @@ export const ANALYTICS_TICK_MS = 1000
15
15
 
16
16
  let lastSaveTime = 0
17
17
 
18
+ /**
19
+ * The last count a store gave. A store that cannot be read keeps it, rather
20
+ * than failing the tick: the requests that need the store already report
21
+ * it, and a gap in the telemetry would report nothing.
22
+ */
23
+ let lastSessionCount = 0
24
+
18
25
  /**
19
26
  * Flush at most once per `SAVE_THROTTLE_MS`.
20
27
  *
@@ -44,12 +51,16 @@ async function runAnalyticsTick(server: any) {
44
51
  return res.status === 200 ? getElapsed(pingStart) : res.status
45
52
  }, 0)
46
53
 
54
+ // Asked of whichever store holds the sessions: a COUNT(*) on the built-in
55
+ // one's SQLite file, one over the `expires_at` index on a database store.
56
+ lastSessionCount = await Try.return(() => Session.total(), lastSessionCount)
57
+
47
58
  const mem = process.memoryUsage()
48
59
  core.pushAnalyticsSnapshot({
49
60
  timestamp: Date.now(),
50
61
  memoryUsed: Math.round(mem.rss / 1024 / 1024),
51
62
  activeLoggers: activeLoggersCount,
52
- activeSessions: Session.count,
63
+ activeSessions: lastSessionCount,
53
64
  ping: pingVal,
54
65
  })
55
66
 
@@ -128,7 +139,8 @@ let loopRunning = false
128
139
  *
129
140
  * A self-rescheduling `setTimeout`, not `setInterval`. The tick body makes a
130
141
  * full round trip through the server (`MiddlewareHandler`, so `onRequest` and
131
- * every app middleware) plus a `Session.count`, which is a SQLite `COUNT(*)`.
142
+ * every app middleware) plus a `Session.total()`: a SQLite `COUNT(*)` with the
143
+ * built-in store, a query to the database with a database one.
132
144
  * `setInterval` does not wait for an async body, so once p50 exceeded one
133
145
  * second the ticks overlapped and the in-flight pings accumulated, each adding
134
146
  * load that lengthened the next: positive feedback, from the telemetry.