ponder 0.14.13 → 0.15.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.
Files changed (237) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/esm/bin/commands/createViews.js +28 -11
  3. package/dist/esm/bin/commands/createViews.js.map +1 -1
  4. package/dist/esm/bin/commands/dev.js +42 -22
  5. package/dist/esm/bin/commands/dev.js.map +1 -1
  6. package/dist/esm/bin/commands/prune.js +3 -0
  7. package/dist/esm/bin/commands/prune.js.map +1 -1
  8. package/dist/esm/bin/commands/serve.js +4 -1
  9. package/dist/esm/bin/commands/serve.js.map +1 -1
  10. package/dist/esm/bin/commands/start.js +18 -6
  11. package/dist/esm/bin/commands/start.js.map +1 -1
  12. package/dist/esm/bin/isolatedController.js +200 -0
  13. package/dist/esm/bin/isolatedController.js.map +1 -0
  14. package/dist/esm/bin/isolatedWorker.js +146 -0
  15. package/dist/esm/bin/isolatedWorker.js.map +1 -0
  16. package/dist/esm/build/config.js +322 -402
  17. package/dist/esm/build/config.js.map +1 -1
  18. package/dist/esm/build/index.js +8 -11
  19. package/dist/esm/build/index.js.map +1 -1
  20. package/dist/esm/build/pre.js +1 -4
  21. package/dist/esm/build/pre.js.map +1 -1
  22. package/dist/esm/build/schema.js +25 -3
  23. package/dist/esm/build/schema.js.map +1 -1
  24. package/dist/esm/client/index.js +306 -42
  25. package/dist/esm/client/index.js.map +1 -1
  26. package/dist/esm/database/actions.js +264 -104
  27. package/dist/esm/database/actions.js.map +1 -1
  28. package/dist/esm/database/index.js +39 -33
  29. package/dist/esm/database/index.js.map +1 -1
  30. package/dist/esm/database/queryBuilder.js +1 -0
  31. package/dist/esm/database/queryBuilder.js.map +1 -1
  32. package/dist/esm/drizzle/index.js +11 -7
  33. package/dist/esm/drizzle/index.js.map +1 -1
  34. package/dist/esm/drizzle/onchain.js +18 -0
  35. package/dist/esm/drizzle/onchain.js.map +1 -1
  36. package/dist/esm/indexing/client.js +32 -25
  37. package/dist/esm/indexing/client.js.map +1 -1
  38. package/dist/esm/indexing/index.js +110 -178
  39. package/dist/esm/indexing/index.js.map +1 -1
  40. package/dist/esm/indexing/profile.js +1 -1
  41. package/dist/esm/indexing/profile.js.map +1 -1
  42. package/dist/esm/indexing-store/cache.js +196 -274
  43. package/dist/esm/indexing-store/cache.js.map +1 -1
  44. package/dist/esm/indexing-store/historical.js +17 -13
  45. package/dist/esm/indexing-store/historical.js.map +1 -1
  46. package/dist/esm/indexing-store/index.js +10 -1
  47. package/dist/esm/indexing-store/index.js.map +1 -1
  48. package/dist/esm/indexing-store/profile.js +3 -3
  49. package/dist/esm/indexing-store/profile.js.map +1 -1
  50. package/dist/esm/indexing-store/realtime.js +27 -2
  51. package/dist/esm/indexing-store/realtime.js.map +1 -1
  52. package/dist/esm/internal/errors.js +28 -0
  53. package/dist/esm/internal/errors.js.map +1 -1
  54. package/dist/esm/internal/metrics.js +279 -82
  55. package/dist/esm/internal/metrics.js.map +1 -1
  56. package/dist/esm/internal/options.js +1 -0
  57. package/dist/esm/internal/options.js.map +1 -1
  58. package/dist/esm/internal/telemetry.js +1 -1
  59. package/dist/esm/internal/telemetry.js.map +1 -1
  60. package/dist/esm/rpc/http.js +130 -0
  61. package/dist/esm/rpc/http.js.map +1 -0
  62. package/dist/esm/rpc/index.js +38 -7
  63. package/dist/esm/rpc/index.js.map +1 -1
  64. package/dist/esm/runtime/events.js +179 -212
  65. package/dist/esm/runtime/events.js.map +1 -1
  66. package/dist/esm/runtime/filter.js +71 -0
  67. package/dist/esm/runtime/filter.js.map +1 -1
  68. package/dist/esm/runtime/fragments.js +78 -73
  69. package/dist/esm/runtime/fragments.js.map +1 -1
  70. package/dist/esm/runtime/historical.js +306 -130
  71. package/dist/esm/runtime/historical.js.map +1 -1
  72. package/dist/esm/runtime/index.js +183 -58
  73. package/dist/esm/runtime/index.js.map +1 -1
  74. package/dist/esm/runtime/isolated.js +462 -0
  75. package/dist/esm/runtime/isolated.js.map +1 -0
  76. package/dist/esm/runtime/multichain.js +80 -73
  77. package/dist/esm/runtime/multichain.js.map +1 -1
  78. package/dist/esm/runtime/omnichain.js +82 -75
  79. package/dist/esm/runtime/omnichain.js.map +1 -1
  80. package/dist/esm/runtime/realtime.js +198 -66
  81. package/dist/esm/runtime/realtime.js.map +1 -1
  82. package/dist/esm/sync-historical/index.js +416 -457
  83. package/dist/esm/sync-historical/index.js.map +1 -1
  84. package/dist/esm/sync-realtime/bloom.js +3 -3
  85. package/dist/esm/sync-realtime/bloom.js.map +1 -1
  86. package/dist/esm/sync-realtime/index.js +27 -46
  87. package/dist/esm/sync-realtime/index.js.map +1 -1
  88. package/dist/esm/sync-store/index.js +112 -63
  89. package/dist/esm/sync-store/index.js.map +1 -1
  90. package/dist/esm/utils/abi.js +20 -32
  91. package/dist/esm/utils/abi.js.map +1 -1
  92. package/dist/esm/utils/chunk.js +8 -0
  93. package/dist/esm/utils/chunk.js.map +1 -0
  94. package/dist/esm/utils/promiseAllSettledWithThrow.js +19 -0
  95. package/dist/esm/utils/promiseAllSettledWithThrow.js.map +1 -0
  96. package/dist/esm/{client/parse.js → utils/sql-parse.js} +94 -80
  97. package/dist/esm/utils/sql-parse.js.map +1 -0
  98. package/dist/types/bin/commands/createViews.d.ts.map +1 -1
  99. package/dist/types/bin/commands/dev.d.ts.map +1 -1
  100. package/dist/types/bin/commands/prune.d.ts.map +1 -1
  101. package/dist/types/bin/commands/serve.d.ts.map +1 -1
  102. package/dist/types/bin/commands/start.d.ts.map +1 -1
  103. package/dist/types/bin/isolatedController.d.ts +13 -0
  104. package/dist/types/bin/isolatedController.d.ts.map +1 -0
  105. package/dist/types/bin/isolatedWorker.d.ts +9 -0
  106. package/dist/types/bin/isolatedWorker.d.ts.map +1 -0
  107. package/dist/types/build/config.d.ts +29 -11
  108. package/dist/types/build/config.d.ts.map +1 -1
  109. package/dist/types/build/index.d.ts +3 -2
  110. package/dist/types/build/index.d.ts.map +1 -1
  111. package/dist/types/build/pre.d.ts +1 -1
  112. package/dist/types/build/pre.d.ts.map +1 -1
  113. package/dist/types/build/schema.d.ts +5 -3
  114. package/dist/types/build/schema.d.ts.map +1 -1
  115. package/dist/types/client/index.d.ts +1 -1
  116. package/dist/types/client/index.d.ts.map +1 -1
  117. package/dist/types/config/index.d.ts +3 -3
  118. package/dist/types/config/index.d.ts.map +1 -1
  119. package/dist/types/database/actions.d.ts +53 -7
  120. package/dist/types/database/actions.d.ts.map +1 -1
  121. package/dist/types/database/index.d.ts +21 -21
  122. package/dist/types/database/index.d.ts.map +1 -1
  123. package/dist/types/database/queryBuilder.d.ts.map +1 -1
  124. package/dist/types/drizzle/index.d.ts +4 -5
  125. package/dist/types/drizzle/index.d.ts.map +1 -1
  126. package/dist/types/drizzle/onchain.d.ts +6 -0
  127. package/dist/types/drizzle/onchain.d.ts.map +1 -1
  128. package/dist/types/indexing/client.d.ts.map +1 -1
  129. package/dist/types/indexing/index.d.ts +2 -5
  130. package/dist/types/indexing/index.d.ts.map +1 -1
  131. package/dist/types/indexing-store/cache.d.ts +3 -2
  132. package/dist/types/indexing-store/cache.d.ts.map +1 -1
  133. package/dist/types/indexing-store/historical.d.ts +2 -1
  134. package/dist/types/indexing-store/historical.d.ts.map +1 -1
  135. package/dist/types/indexing-store/index.d.ts +1 -0
  136. package/dist/types/indexing-store/index.d.ts.map +1 -1
  137. package/dist/types/indexing-store/realtime.d.ts +2 -1
  138. package/dist/types/indexing-store/realtime.d.ts.map +1 -1
  139. package/dist/types/internal/errors.d.ts +5 -0
  140. package/dist/types/internal/errors.d.ts.map +1 -1
  141. package/dist/types/internal/metrics.d.ts +21 -0
  142. package/dist/types/internal/metrics.d.ts.map +1 -1
  143. package/dist/types/internal/options.d.ts +2 -0
  144. package/dist/types/internal/options.d.ts.map +1 -1
  145. package/dist/types/internal/types.d.ts +66 -58
  146. package/dist/types/internal/types.d.ts.map +1 -1
  147. package/dist/types/rpc/http.d.ts +17 -0
  148. package/dist/types/rpc/http.d.ts.map +1 -0
  149. package/dist/types/rpc/index.d.ts.map +1 -1
  150. package/dist/types/runtime/events.d.ts +4 -4
  151. package/dist/types/runtime/events.d.ts.map +1 -1
  152. package/dist/types/runtime/filter.d.ts +5 -1
  153. package/dist/types/runtime/filter.d.ts.map +1 -1
  154. package/dist/types/runtime/fragments.d.ts +4 -3
  155. package/dist/types/runtime/fragments.d.ts.map +1 -1
  156. package/dist/types/runtime/historical.d.ts +29 -13
  157. package/dist/types/runtime/historical.d.ts.map +1 -1
  158. package/dist/types/runtime/index.d.ts +49 -6
  159. package/dist/types/runtime/index.d.ts.map +1 -1
  160. package/dist/types/runtime/init.d.ts +5 -5
  161. package/dist/types/runtime/init.d.ts.map +1 -1
  162. package/dist/types/runtime/isolated.d.ts +14 -0
  163. package/dist/types/runtime/isolated.d.ts.map +1 -0
  164. package/dist/types/runtime/multichain.d.ts.map +1 -1
  165. package/dist/types/runtime/omnichain.d.ts.map +1 -1
  166. package/dist/types/runtime/realtime.d.ts +21 -10
  167. package/dist/types/runtime/realtime.d.ts.map +1 -1
  168. package/dist/types/sync-historical/index.d.ts +18 -8
  169. package/dist/types/sync-historical/index.d.ts.map +1 -1
  170. package/dist/types/sync-realtime/bloom.d.ts.map +1 -1
  171. package/dist/types/sync-realtime/index.d.ts +2 -2
  172. package/dist/types/sync-realtime/index.d.ts.map +1 -1
  173. package/dist/types/sync-store/index.d.ts +9 -9
  174. package/dist/types/sync-store/index.d.ts.map +1 -1
  175. package/dist/types/utils/abi.d.ts +3 -34
  176. package/dist/types/utils/abi.d.ts.map +1 -1
  177. package/dist/types/utils/chunk.d.ts +2 -0
  178. package/dist/types/utils/chunk.d.ts.map +1 -0
  179. package/dist/types/utils/promiseAllSettledWithThrow.d.ts +8 -0
  180. package/dist/types/utils/promiseAllSettledWithThrow.d.ts.map +1 -0
  181. package/dist/types/utils/sql-parse.d.ts +21 -0
  182. package/dist/types/utils/sql-parse.d.ts.map +1 -0
  183. package/package.json +2 -2
  184. package/src/bin/commands/createViews.ts +35 -15
  185. package/src/bin/commands/dev.ts +43 -21
  186. package/src/bin/commands/prune.ts +6 -0
  187. package/src/bin/commands/serve.ts +4 -1
  188. package/src/bin/commands/start.ts +20 -5
  189. package/src/bin/isolatedController.ts +300 -0
  190. package/src/bin/isolatedWorker.ts +192 -0
  191. package/src/build/config.ts +570 -632
  192. package/src/build/index.ts +14 -14
  193. package/src/build/pre.ts +1 -4
  194. package/src/build/schema.ts +49 -4
  195. package/src/client/index.ts +386 -48
  196. package/src/config/index.ts +3 -3
  197. package/src/database/actions.ts +469 -120
  198. package/src/database/index.ts +85 -58
  199. package/src/database/queryBuilder.ts +1 -0
  200. package/src/drizzle/index.ts +15 -7
  201. package/src/drizzle/onchain.ts +19 -0
  202. package/src/indexing/client.ts +38 -25
  203. package/src/indexing/index.ts +137 -230
  204. package/src/indexing/profile.ts +1 -1
  205. package/src/indexing-store/cache.ts +285 -414
  206. package/src/indexing-store/historical.ts +20 -10
  207. package/src/indexing-store/index.ts +16 -0
  208. package/src/indexing-store/profile.ts +3 -3
  209. package/src/indexing-store/realtime.ts +28 -0
  210. package/src/internal/errors.ts +26 -0
  211. package/src/internal/metrics.ts +341 -111
  212. package/src/internal/options.ts +4 -0
  213. package/src/internal/telemetry.ts +1 -1
  214. package/src/internal/types.ts +70 -87
  215. package/src/rpc/http.ts +164 -0
  216. package/src/rpc/index.ts +39 -7
  217. package/src/runtime/events.ts +195 -240
  218. package/src/runtime/filter.ts +85 -1
  219. package/src/runtime/fragments.ts +109 -113
  220. package/src/runtime/historical.ts +467 -189
  221. package/src/runtime/index.ts +337 -69
  222. package/src/runtime/init.ts +5 -5
  223. package/src/runtime/isolated.ts +768 -0
  224. package/src/runtime/multichain.ts +137 -102
  225. package/src/runtime/omnichain.ts +138 -106
  226. package/src/runtime/realtime.ts +322 -123
  227. package/src/sync-historical/index.ts +556 -692
  228. package/src/sync-realtime/bloom.ts +7 -3
  229. package/src/sync-realtime/index.ts +31 -46
  230. package/src/sync-store/index.ts +189 -95
  231. package/src/utils/abi.ts +33 -90
  232. package/src/utils/chunk.ts +7 -0
  233. package/src/utils/promiseAllSettledWithThrow.ts +27 -0
  234. package/src/{client/parse.ts → utils/sql-parse.ts} +100 -90
  235. package/dist/esm/client/parse.js.map +0 -1
  236. package/dist/types/client/parse.d.ts +0 -14
  237. package/dist/types/client/parse.d.ts.map +0 -1
@@ -1,7 +1,12 @@
1
+ import { type Worker, parentPort } from "node:worker_threads";
2
+ import {
3
+ type PromiseWithResolvers,
4
+ promiseWithResolvers,
5
+ } from "@/utils/promiseWithResolvers.js";
1
6
  import { truncate } from "@/utils/truncate.js";
2
7
  import { getTableName, isTable } from "drizzle-orm";
3
8
  import prometheus from "prom-client";
4
- import type { IndexingBuild, SchemaBuild } from "./types.js";
9
+ import type { IndexingBuild, PreBuild, SchemaBuild } from "./types.js";
5
10
 
6
11
  const sometimesIODurationMs = [
7
12
  0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, 10, 50, 100, 500, 1_000, 5_000,
@@ -17,6 +22,9 @@ const httpRequestSizeBytes = [
17
22
  10_000_000,
18
23
  ];
19
24
 
25
+ const GET_METRICS_REQ = "prom-client:getMetricsReq";
26
+ const GET_METRICS_RES = "prom-client:getMetricsRes";
27
+
20
28
  export class MetricsService {
21
29
  registry: prometheus.Registry;
22
30
  start_timestamp: number;
@@ -124,12 +132,14 @@ export class MetricsService {
124
132
  help: "Ponder version information",
125
133
  labelNames: ["version", "major", "minor", "patch"] as const,
126
134
  registers: [this.registry],
135
+ aggregator: "first",
127
136
  });
128
137
  this.ponder_settings_info = new prometheus.Gauge({
129
138
  name: "ponder_settings_info",
130
139
  help: "Ponder settings information",
131
140
  labelNames: ["ordering", "database", "command"] as const,
132
141
  registers: [this.registry],
142
+ aggregator: "first",
133
143
  });
134
144
 
135
145
  this.ponder_historical_concurrency_group_duration = new prometheus.Gauge({
@@ -137,18 +147,21 @@ export class MetricsService {
137
147
  help: "Duration of historical concurrency groups",
138
148
  labelNames: ["group"] as const,
139
149
  registers: [this.registry],
150
+ aggregator: "sum",
140
151
  });
141
152
  this.ponder_historical_extract_duration = new prometheus.Gauge({
142
153
  name: "ponder_historical_extract_duration",
143
154
  help: "Duration of historical extract phase",
144
155
  labelNames: ["step"] as const,
145
156
  registers: [this.registry],
157
+ aggregator: "sum",
146
158
  });
147
159
  this.ponder_historical_transform_duration = new prometheus.Gauge({
148
160
  name: "ponder_historical_transform_duration",
149
161
  help: "Duration of historical transform phase",
150
162
  labelNames: ["step"] as const,
151
163
  registers: [this.registry],
164
+ aggregator: "sum",
152
165
  });
153
166
 
154
167
  this.ponder_historical_start_timestamp_seconds = new prometheus.Gauge({
@@ -156,12 +169,14 @@ export class MetricsService {
156
169
  help: "Timestamp at which historical indexing started",
157
170
  labelNames: ["chain"] as const,
158
171
  registers: [this.registry],
172
+ aggregator: "min",
159
173
  });
160
174
  this.ponder_historical_end_timestamp_seconds = new prometheus.Gauge({
161
175
  name: "ponder_historical_end_timestamp_seconds",
162
176
  help: "Timestamp at which historical indexing ended",
163
177
  labelNames: ["chain"] as const,
164
178
  registers: [this.registry],
179
+ aggregator: "max",
165
180
  });
166
181
 
167
182
  this.ponder_historical_total_indexing_seconds = new prometheus.Gauge({
@@ -169,30 +184,35 @@ export class MetricsService {
169
184
  help: "Total number of seconds that are required",
170
185
  labelNames: ["chain"] as const,
171
186
  registers: [this.registry],
187
+ aggregator: "sum",
172
188
  });
173
189
  this.ponder_historical_cached_indexing_seconds = new prometheus.Gauge({
174
190
  name: "ponder_historical_cached_indexing_seconds",
175
191
  help: "Number of seconds that have been cached",
176
192
  labelNames: ["chain"] as const,
177
193
  registers: [this.registry],
194
+ aggregator: "sum",
178
195
  });
179
196
  this.ponder_historical_completed_indexing_seconds = new prometheus.Gauge({
180
197
  name: "ponder_historical_completed_indexing_seconds",
181
198
  help: "Number of seconds that have been completed",
182
199
  labelNames: ["chain"] as const,
183
200
  registers: [this.registry],
201
+ aggregator: "sum",
184
202
  });
185
203
  this.ponder_indexing_completed_events = new prometheus.Gauge({
186
204
  name: "ponder_indexing_completed_events",
187
205
  help: "Number of events that have been processed",
188
206
  labelNames: ["chain", "event"] as const,
189
207
  registers: [this.registry],
208
+ aggregator: "sum",
190
209
  });
191
210
  this.ponder_indexing_timestamp = new prometheus.Gauge({
192
211
  name: "ponder_indexing_timestamp",
193
212
  help: "Timestamp through which all events have been completed",
194
213
  labelNames: ["chain"] as const,
195
214
  registers: [this.registry],
215
+ aggregator: "first",
196
216
  });
197
217
  this.ponder_indexing_function_duration = new prometheus.Histogram({
198
218
  name: "ponder_indexing_function_duration",
@@ -200,6 +220,7 @@ export class MetricsService {
200
220
  labelNames: ["chain", "event"] as const,
201
221
  buckets: sometimesIODurationMs,
202
222
  registers: [this.registry],
223
+ aggregator: "sum",
203
224
  });
204
225
  this.ponder_indexing_cache_query_duration = new prometheus.Histogram({
205
226
  name: "ponder_indexing_cache_query_duration",
@@ -207,6 +228,7 @@ export class MetricsService {
207
228
  labelNames: ["table", "method"] as const,
208
229
  buckets: alwaysIODurationMs,
209
230
  registers: [this.registry],
231
+ aggregator: "sum",
210
232
  });
211
233
  this.ponder_indexing_rpc_action_duration = new prometheus.Histogram({
212
234
  name: "ponder_indexing_rpc_action_duration",
@@ -214,36 +236,42 @@ export class MetricsService {
214
236
  labelNames: ["action"] as const,
215
237
  buckets: sometimesIODurationMs,
216
238
  registers: [this.registry],
239
+ aggregator: "sum",
217
240
  });
218
241
  this.ponder_indexing_rpc_prefetch_total = new prometheus.Counter({
219
242
  name: "ponder_indexing_rpc_prefetch_total",
220
243
  help: "Number of RPC prefetches",
221
244
  labelNames: ["chain", "method", "type"] as const,
222
245
  registers: [this.registry],
246
+ aggregator: "sum",
223
247
  });
224
248
  this.ponder_indexing_rpc_requests_total = new prometheus.Counter({
225
249
  name: "ponder_indexing_rpc_requests_total",
226
250
  help: "Number of RPC requests",
227
251
  labelNames: ["chain", "method", "type"] as const,
228
252
  registers: [this.registry],
253
+ aggregator: "sum",
229
254
  });
230
255
  this.ponder_indexing_cache_requests_total = new prometheus.Counter({
231
256
  name: "ponder_indexing_cache_requests_total",
232
257
  help: "Number of cache accesses",
233
258
  labelNames: ["table", "type"] as const,
234
259
  registers: [this.registry],
260
+ aggregator: "sum",
235
261
  });
236
262
  this.ponder_indexing_store_queries_total = new prometheus.Counter({
237
263
  name: "ponder_indexing_store_queries_total",
238
264
  help: "Number of indexing store operations",
239
265
  labelNames: ["table", "method"] as const,
240
266
  registers: [this.registry],
267
+ aggregator: "sum",
241
268
  });
242
269
  this.ponder_indexing_store_raw_sql_duration = new prometheus.Histogram({
243
270
  name: "ponder_indexing_store_raw_sql_duration",
244
271
  help: "Duration of raw SQL store operations",
245
272
  buckets: alwaysIODurationMs,
246
273
  registers: [this.registry],
274
+ aggregator: "sum",
247
275
  });
248
276
 
249
277
  this.ponder_sync_block = new prometheus.Gauge({
@@ -251,24 +279,28 @@ export class MetricsService {
251
279
  help: "Closest-to-tip synced block number",
252
280
  labelNames: ["chain"] as const,
253
281
  registers: [this.registry],
282
+ aggregator: "max",
254
283
  });
255
284
  this.ponder_sync_block_timestamp = new prometheus.Gauge({
256
285
  name: "ponder_sync_block_timestamp",
257
286
  help: "Closest-to-tip synced block timestamp",
258
287
  labelNames: ["chain"] as const,
259
288
  registers: [this.registry],
289
+ aggregator: "max",
260
290
  });
261
291
  this.ponder_sync_is_realtime = new prometheus.Gauge({
262
292
  name: "ponder_sync_is_realtime",
263
293
  help: "Boolean (0 or 1) indicating if the sync is realtime mode",
264
294
  labelNames: ["chain"] as const,
265
295
  registers: [this.registry],
296
+ aggregator: "max",
266
297
  });
267
298
  this.ponder_sync_is_complete = new prometheus.Gauge({
268
299
  name: "ponder_sync_is_complete",
269
300
  help: "Boolean (0 or 1) indicating if the sync has synced all blocks",
270
301
  labelNames: ["chain"] as const,
271
302
  registers: [this.registry],
303
+ aggregator: "max",
272
304
  });
273
305
 
274
306
  this.ponder_historical_total_blocks = new prometheus.Gauge({
@@ -276,18 +308,21 @@ export class MetricsService {
276
308
  help: "Number of blocks required for the historical sync",
277
309
  labelNames: ["chain"] as const,
278
310
  registers: [this.registry],
311
+ aggregator: "max",
279
312
  });
280
313
  this.ponder_historical_cached_blocks = new prometheus.Gauge({
281
314
  name: "ponder_historical_cached_blocks",
282
315
  help: "Number of blocks that were found in the cache for the historical sync",
283
316
  labelNames: ["chain"] as const,
284
317
  registers: [this.registry],
318
+ aggregator: "max",
285
319
  });
286
320
  this.ponder_historical_completed_blocks = new prometheus.Gauge({
287
321
  name: "ponder_historical_completed_blocks",
288
322
  help: "Number of blocks that have been processed for the historical sync",
289
323
  labelNames: ["chain", "source", "type"] as const,
290
324
  registers: [this.registry],
325
+ aggregator: "max",
291
326
  });
292
327
 
293
328
  this.ponder_realtime_reorg_total = new prometheus.Counter({
@@ -295,6 +330,7 @@ export class MetricsService {
295
330
  help: "Count of how many re-orgs have occurred",
296
331
  labelNames: ["chain"] as const,
297
332
  registers: [this.registry],
333
+ aggregator: "sum",
298
334
  });
299
335
  this.ponder_realtime_latency = new prometheus.Histogram({
300
336
  name: "ponder_realtime_latency",
@@ -305,6 +341,7 @@ export class MetricsService {
305
341
  1_000_000,
306
342
  ],
307
343
  registers: [this.registry],
344
+ aggregator: "sum",
308
345
  });
309
346
  this.ponder_realtime_block_arrival_latency = new prometheus.Histogram({
310
347
  name: "ponder_realtime_block_arrival_latency",
@@ -315,6 +352,7 @@ export class MetricsService {
315
352
  1_000_000,
316
353
  ],
317
354
  registers: [this.registry],
355
+ aggregator: "sum",
318
356
  });
319
357
 
320
358
  this.ponder_database_method_duration = new prometheus.Histogram({
@@ -323,18 +361,21 @@ export class MetricsService {
323
361
  labelNames: ["service", "method"] as const,
324
362
  buckets: alwaysIODurationMs,
325
363
  registers: [this.registry],
364
+ aggregator: "sum",
326
365
  });
327
366
  this.ponder_database_method_error_total = new prometheus.Counter({
328
367
  name: "ponder_database_method_error_total",
329
368
  help: "Total number of errors encountered during database operations",
330
369
  labelNames: ["service", "method"] as const,
331
370
  registers: [this.registry],
371
+ aggregator: "sum",
332
372
  });
333
373
  this.ponder_http_server_active_requests = new prometheus.Gauge({
334
374
  name: "ponder_http_server_active_requests",
335
375
  help: "Number of active HTTP server requests",
336
376
  labelNames: ["method", "path"] as const,
337
377
  registers: [this.registry],
378
+ aggregator: "sum",
338
379
  });
339
380
  this.ponder_http_server_request_duration_ms = new prometheus.Histogram({
340
381
  name: "ponder_http_server_request_duration_ms",
@@ -342,6 +383,7 @@ export class MetricsService {
342
383
  labelNames: ["method", "path", "status"] as const,
343
384
  buckets: alwaysIODurationMs,
344
385
  registers: [this.registry],
386
+ aggregator: "sum",
345
387
  });
346
388
  this.ponder_http_server_request_size_bytes = new prometheus.Histogram({
347
389
  name: "ponder_http_server_request_size_bytes",
@@ -349,6 +391,7 @@ export class MetricsService {
349
391
  labelNames: ["method", "path", "status"] as const,
350
392
  buckets: httpRequestSizeBytes,
351
393
  registers: [this.registry],
394
+ aggregator: "sum",
352
395
  });
353
396
  this.ponder_http_server_response_size_bytes = new prometheus.Histogram({
354
397
  name: "ponder_http_server_response_size_bytes",
@@ -356,6 +399,7 @@ export class MetricsService {
356
399
  labelNames: ["method", "path", "status"] as const,
357
400
  buckets: httpRequestSizeBytes,
358
401
  registers: [this.registry],
402
+ aggregator: "sum",
359
403
  });
360
404
 
361
405
  this.ponder_rpc_request_duration = new prometheus.Histogram({
@@ -364,6 +408,7 @@ export class MetricsService {
364
408
  labelNames: ["chain", "method"] as const,
365
409
  buckets: alwaysIODurationMs,
366
410
  registers: [this.registry],
411
+ aggregator: "sum",
367
412
  });
368
413
 
369
414
  this.ponder_rpc_request_error_total = new prometheus.Counter({
@@ -371,6 +416,7 @@ export class MetricsService {
371
416
  help: "Total count of failed RPC requests",
372
417
  labelNames: ["chain", "method"] as const,
373
418
  registers: [this.registry],
419
+ aggregator: "sum",
374
420
  });
375
421
 
376
422
  this.ponder_postgres_query_total = new prometheus.Counter({
@@ -378,6 +424,7 @@ export class MetricsService {
378
424
  help: "Total number of queries submitted to the database",
379
425
  labelNames: ["pool"] as const,
380
426
  registers: [this.registry],
427
+ aggregator: "sum",
381
428
  });
382
429
 
383
430
  prometheus.collectDefaultMetrics({
@@ -391,8 +438,12 @@ export class MetricsService {
391
438
  * Get string representation for all metrics.
392
439
  * @returns Metrics encoded using Prometheus v0.0.4 format.
393
440
  */
394
- async getMetrics() {
395
- return await this.registry.metrics();
441
+ getMetrics() {
442
+ return this.registry.metrics();
443
+ }
444
+
445
+ async getRegistry() {
446
+ return this.registry;
396
447
  }
397
448
 
398
449
  initializeIndexingMetrics({
@@ -404,8 +455,8 @@ export class MetricsService {
404
455
  }) {
405
456
  const tables = Object.values(schemaBuild.schema).filter(isTable);
406
457
 
407
- for (const event of Object.keys(indexingBuild.indexingFunctions)) {
408
- this.ponder_indexing_completed_events.inc({ event }, 0);
458
+ for (const { name: eventName } of indexingBuild.indexingFunctions) {
459
+ this.ponder_indexing_completed_events.inc({ event: eventName }, 0);
409
460
  }
410
461
 
411
462
  for (const table of tables) {
@@ -477,6 +528,168 @@ export class MetricsService {
477
528
  }
478
529
  }
479
530
 
531
+ type MetricsAggregationRequest = {
532
+ type: typeof GET_METRICS_REQ;
533
+ requestId: number;
534
+ };
535
+ type MetricsAggregationResponse = {
536
+ type: typeof GET_METRICS_RES;
537
+ requestId: number;
538
+ error?: string;
539
+ metrics: prometheus.MetricObjectWithValues<prometheus.MetricValue<string>>[];
540
+ };
541
+
542
+ export class AggregateMetricsService extends MetricsService {
543
+ workers: Worker[];
544
+ requests: Map<
545
+ number,
546
+ {
547
+ responses: prometheus.MetricObjectWithValues<
548
+ prometheus.MetricValue<string>
549
+ >[][];
550
+ workerIds: number[];
551
+ pending: number;
552
+ pwr: PromiseWithResolvers<void>;
553
+ }
554
+ >;
555
+ requestId: number;
556
+ mainThreadMetrics: MetricsService;
557
+
558
+ constructor(mainThreadMetrics: MetricsService, workers: Worker[]) {
559
+ super();
560
+
561
+ this.mainThreadMetrics = mainThreadMetrics;
562
+ this.workers = workers;
563
+ this.requests = new Map();
564
+ this.requestId = 0;
565
+
566
+ for (const worker of workers) {
567
+ worker.on("message", (message: MetricsAggregationResponse) => {
568
+ if (message.type === GET_METRICS_RES) {
569
+ const request = this.requests.get(message.requestId);
570
+
571
+ if (request === undefined) return;
572
+
573
+ if (message.error) {
574
+ request.pwr.reject(new Error(message.error));
575
+ return;
576
+ }
577
+
578
+ request.responses.push(message.metrics);
579
+ request.workerIds.push(worker.threadId);
580
+ request.pending--;
581
+ if (request.pending === 0) {
582
+ request.pwr.resolve();
583
+ }
584
+ }
585
+ });
586
+ }
587
+ }
588
+
589
+ override async getMetrics() {
590
+ const requestId = this.requestId++;
591
+ const pwr = promiseWithResolvers<void>();
592
+
593
+ this.requests.set(requestId, {
594
+ responses: [],
595
+ workerIds: [],
596
+ pending: this.workers.length,
597
+ pwr,
598
+ });
599
+
600
+ for (const worker of this.workers) {
601
+ worker.postMessage({
602
+ type: GET_METRICS_REQ,
603
+ requestId,
604
+ } satisfies MetricsAggregationRequest);
605
+ }
606
+
607
+ await pwr.promise;
608
+
609
+ const request = this.requests.get(requestId)!;
610
+ this.requests.delete(requestId);
611
+
612
+ // Sort response by worker id for consistent metrics
613
+ const responseIndexSort = new Array(this.workers.length)
614
+ .fill(0)
615
+ .map((_, index) => index)
616
+ .sort((a, b) => request.workerIds[a]! - request.workerIds[b]!);
617
+
618
+ return prometheus.AggregatorRegistry.aggregate([
619
+ ...responseIndexSort.map((index) => request.responses[index]!),
620
+ await this.registry.getMetricsAsJSON(),
621
+ await this.mainThreadMetrics.registry.getMetricsAsJSON(),
622
+ ]).metrics();
623
+ }
624
+
625
+ override async getRegistry() {
626
+ const requestId = this.requestId++;
627
+ const pwr = promiseWithResolvers<void>();
628
+
629
+ this.requests.set(requestId, {
630
+ responses: [],
631
+ workerIds: [],
632
+ pending: this.workers.length,
633
+ pwr,
634
+ });
635
+
636
+ for (const worker of this.workers) {
637
+ worker.postMessage({
638
+ type: GET_METRICS_REQ,
639
+ requestId,
640
+ } satisfies MetricsAggregationRequest);
641
+ }
642
+
643
+ await pwr.promise;
644
+
645
+ const request = this.requests.get(requestId)!;
646
+ this.requests.delete(requestId);
647
+
648
+ // Sort response by worker id for consistent metrics
649
+ const responseIndexSort = new Array(this.workers.length)
650
+ .fill(0)
651
+ .map((_, index) => index)
652
+ .sort((a, b) => request.workerIds[a]! - request.workerIds[b]!);
653
+
654
+ return prometheus.AggregatorRegistry.aggregate([
655
+ ...responseIndexSort.map((index) => request.responses[index]!),
656
+ await this.registry.getMetricsAsJSON(),
657
+ await this.mainThreadMetrics.registry.getMetricsAsJSON(),
658
+ ]) as prometheus.Registry;
659
+ }
660
+
661
+ // Note: `resetIndexingMetrics` and `resetApiMetrics` are never called with `AggregateMetricsService`.
662
+ }
663
+
664
+ export class IsolatedMetricsService extends MetricsService {
665
+ constructor() {
666
+ super();
667
+
668
+ if (parentPort) {
669
+ parentPort.on("message", (message: MetricsAggregationRequest) => {
670
+ if (message.type === GET_METRICS_REQ) {
671
+ this.registry
672
+ .getMetricsAsJSON()
673
+ .then((metrics) => {
674
+ parentPort!.postMessage({
675
+ type: GET_METRICS_RES,
676
+ requestId: message.requestId,
677
+ metrics,
678
+ });
679
+ })
680
+ .catch((error) => {
681
+ parentPort!.postMessage({
682
+ type: GET_METRICS_RES,
683
+ requestId: message.requestId,
684
+ error: error.message,
685
+ });
686
+ });
687
+ }
688
+ });
689
+ }
690
+ }
691
+ }
692
+
480
693
  const extractMetric = (
481
694
  metric: prometheus.MetricObjectWithValues<prometheus.MetricValue<"chain">>,
482
695
  chain: string,
@@ -596,44 +809,48 @@ export async function getAppProgress(metrics: MetricsService): Promise<{
596
809
  progress: number | undefined;
597
810
  eta: number | undefined;
598
811
  }> {
599
- const totalSecondsMetric =
600
- await metrics.ponder_historical_total_indexing_seconds.get();
601
- const cachedSecondsMetric =
602
- await metrics.ponder_historical_cached_indexing_seconds.get();
603
- const completedSecondsMetric =
604
- await metrics.ponder_historical_completed_indexing_seconds.get();
605
- const timestampMetric = await metrics.ponder_indexing_timestamp.get();
606
-
607
- const ordering: "multichain" | "omnichain" | undefined =
608
- await metrics.ponder_settings_info
609
- .get()
610
- .then((metric) => metric.values[0]?.labels.ordering as any);
611
- if (ordering === undefined) {
612
- return {
613
- mode: "backfill",
614
- progress: undefined,
615
- eta: undefined,
616
- };
617
- } else if (ordering === "multichain") {
618
- const perChainAppProgress: Awaited<ReturnType<typeof getAppProgress>>[] =
619
- [];
620
-
621
- for (const chainName of totalSecondsMetric.values.map(
622
- ({ labels }) => labels.chain as string,
623
- )) {
624
- const totalSeconds = extractMetric(totalSecondsMetric, chainName);
625
- const cachedSeconds = extractMetric(cachedSecondsMetric, chainName);
626
- const completedSeconds = extractMetric(completedSecondsMetric, chainName);
627
- const timestamp = extractMetric(timestampMetric, chainName);
628
-
629
- if (
630
- totalSeconds === undefined ||
631
- cachedSeconds === undefined ||
632
- completedSeconds === undefined ||
633
- timestamp === undefined
634
- ) {
635
- continue;
636
- }
812
+ // Note: `getRegistry` must be used because this function is used with "experimental_isolated" ordering.
813
+ const registry = await metrics.getRegistry();
814
+
815
+ const totalSecondsMetric = await registry
816
+ .getSingleMetric("ponder_historical_total_indexing_seconds")!
817
+ .get();
818
+ const cachedSecondsMetric = await registry
819
+ .getSingleMetric("ponder_historical_cached_indexing_seconds")!
820
+ .get();
821
+ const completedSecondsMetric = await registry
822
+ .getSingleMetric("ponder_historical_completed_indexing_seconds")!
823
+ .get();
824
+ const timestampMetric = await registry
825
+ .getSingleMetric("ponder_indexing_timestamp")!
826
+ .get();
827
+
828
+ const settingsMetric = await registry
829
+ .getSingleMetric("ponder_settings_info")!
830
+ .get();
831
+ const ordering: PreBuild["ordering"] | undefined = settingsMetric?.values[0]
832
+ ?.labels.ordering as any;
833
+
834
+ switch (ordering) {
835
+ case undefined:
836
+ return {
837
+ mode: "backfill",
838
+ progress: undefined,
839
+ eta: undefined,
840
+ };
841
+ case "omnichain": {
842
+ const totalSeconds = totalSecondsMetric?.values
843
+ .map(({ value }) => value)
844
+ .reduce((prev, curr) => prev + curr, 0);
845
+ const cachedSeconds = cachedSecondsMetric?.values
846
+ .map(({ value }) => value)
847
+ .reduce((prev, curr) => prev + curr, 0);
848
+ const completedSeconds = completedSecondsMetric?.values
849
+ .map(({ value }) => value)
850
+ .reduce((prev, curr) => prev + curr, 0);
851
+ const timestamp = timestampMetric?.values
852
+ .map(({ value }) => value)
853
+ .reduce((prev, curr) => Math.max(prev, curr), 0);
637
854
 
638
855
  const progress =
639
856
  timestamp === 0
@@ -642,79 +859,92 @@ export async function getAppProgress(metrics: MetricsService): Promise<{
642
859
  ? 1
643
860
  : (completedSeconds + cachedSeconds) / totalSeconds;
644
861
 
645
- if (!metrics.progressMetadata[chainName]) {
646
- metrics.progressMetadata[chainName] = {
647
- batches: [{ elapsedSeconds: 0, completedSeconds: 0 }],
648
- previousTimestamp: Date.now(),
649
- previousCompletedSeconds: 0,
650
- rate: 0,
651
- };
652
- }
653
-
654
- const eta: number | undefined = calculateEta(
655
- metrics.progressMetadata[chainName]!,
656
- totalSeconds,
657
- cachedSeconds,
658
- completedSeconds,
659
- );
660
- perChainAppProgress.push({
862
+ return {
661
863
  mode: progress === 1 ? "live" : "backfill",
662
- progress,
663
- eta,
664
- });
864
+ progress: progress,
865
+ eta: calculateEta(
866
+ metrics.progressMetadata.general!,
867
+ totalSeconds,
868
+ cachedSeconds,
869
+ completedSeconds,
870
+ ),
871
+ };
665
872
  }
873
+ case "multichain":
874
+ case "experimental_isolated": {
875
+ const perChainAppProgress: Awaited<ReturnType<typeof getAppProgress>>[] =
876
+ [];
877
+
878
+ for (const chainName of totalSecondsMetric?.values.map(
879
+ ({ labels }) => labels.chain as string,
880
+ ) ?? []) {
881
+ const totalSeconds = extractMetric(totalSecondsMetric, chainName);
882
+ const cachedSeconds = extractMetric(cachedSecondsMetric, chainName);
883
+ const completedSeconds = extractMetric(
884
+ completedSecondsMetric,
885
+ chainName,
886
+ );
887
+ const timestamp = extractMetric(timestampMetric, chainName);
888
+
889
+ if (
890
+ totalSeconds === undefined ||
891
+ cachedSeconds === undefined ||
892
+ completedSeconds === undefined ||
893
+ timestamp === undefined
894
+ ) {
895
+ continue;
896
+ }
666
897
 
667
- return perChainAppProgress.reduce(
668
- (prev, curr) => ({
669
- mode: curr.mode === "backfill" ? curr.mode : prev.mode,
670
- progress:
671
- prev.progress === undefined || curr.progress === undefined
672
- ? undefined
673
- : Math.min(prev.progress, curr.progress),
674
- eta:
675
- curr.progress === 1
676
- ? prev.eta
677
- : prev.eta === undefined || curr.eta === undefined
678
- ? undefined
679
- : Math.max(prev.eta, curr.eta),
680
- }),
681
- {
682
- mode: "live",
683
- progress: 1,
684
- eta: 0,
685
- },
686
- ) as any;
687
- } else {
688
- const totalSeconds = totalSecondsMetric.values
689
- .map(({ value }) => value)
690
- .reduce((prev, curr) => prev + curr, 0);
691
- const cachedSeconds = cachedSecondsMetric.values
692
- .map(({ value }) => value)
693
- .reduce((prev, curr) => prev + curr, 0);
694
- const completedSeconds = completedSecondsMetric.values
695
- .map(({ value }) => value)
696
- .reduce((prev, curr) => prev + curr, 0);
697
- const timestamp = timestampMetric.values
698
- .map(({ value }) => value)
699
- .reduce((prev, curr) => Math.max(prev, curr), 0);
898
+ const progress =
899
+ timestamp === 0
900
+ ? 0
901
+ : totalSeconds === 0
902
+ ? 1
903
+ : (completedSeconds + cachedSeconds) / totalSeconds;
904
+
905
+ if (!metrics.progressMetadata[chainName]) {
906
+ metrics.progressMetadata[chainName] = {
907
+ batches: [{ elapsedSeconds: 0, completedSeconds: 0 }],
908
+ previousTimestamp: Date.now(),
909
+ previousCompletedSeconds: 0,
910
+ rate: 0,
911
+ };
912
+ }
700
913
 
701
- const progress =
702
- timestamp === 0
703
- ? 0
704
- : totalSeconds === 0
705
- ? 1
706
- : (completedSeconds + cachedSeconds) / totalSeconds;
914
+ const eta: number | undefined = calculateEta(
915
+ metrics.progressMetadata[chainName]!,
916
+ totalSeconds,
917
+ cachedSeconds,
918
+ completedSeconds,
919
+ );
920
+ perChainAppProgress.push({
921
+ mode: progress === 1 ? "live" : "backfill",
922
+ progress,
923
+ eta,
924
+ });
925
+ }
707
926
 
708
- return {
709
- mode: progress === 1 ? "live" : "backfill",
710
- progress: progress,
711
- eta: calculateEta(
712
- metrics.progressMetadata.general!,
713
- totalSeconds,
714
- cachedSeconds,
715
- completedSeconds,
716
- ),
717
- };
927
+ return perChainAppProgress.reduce(
928
+ (prev, curr) => ({
929
+ mode: curr.mode === "backfill" ? curr.mode : prev.mode,
930
+ progress:
931
+ prev.progress === undefined || curr.progress === undefined
932
+ ? undefined
933
+ : Math.min(prev.progress, curr.progress),
934
+ eta:
935
+ curr.progress === 1
936
+ ? prev.eta
937
+ : prev.eta === undefined || curr.eta === undefined
938
+ ? undefined
939
+ : Math.max(prev.eta, curr.eta),
940
+ }),
941
+ {
942
+ mode: "live",
943
+ progress: 1,
944
+ eta: 0,
945
+ },
946
+ );
947
+ }
718
948
  }
719
949
  }
720
950