@powersync/service-core 1.10.1 → 1.11.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 (96) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/api/api-index.d.ts +1 -0
  3. package/dist/api/api-index.js +1 -0
  4. package/dist/api/api-index.js.map +1 -1
  5. package/dist/api/api-metrics.d.ts +11 -0
  6. package/dist/api/api-metrics.js +30 -0
  7. package/dist/api/api-metrics.js.map +1 -0
  8. package/dist/index.d.ts +2 -2
  9. package/dist/index.js +2 -2
  10. package/dist/index.js.map +1 -1
  11. package/dist/metrics/MetricsEngine.d.ts +21 -0
  12. package/dist/metrics/MetricsEngine.js +79 -0
  13. package/dist/metrics/MetricsEngine.js.map +1 -0
  14. package/dist/metrics/metrics-index.d.ts +5 -0
  15. package/dist/metrics/metrics-index.js +6 -0
  16. package/dist/metrics/metrics-index.js.map +1 -0
  17. package/dist/metrics/metrics-interfaces.d.ts +36 -0
  18. package/dist/metrics/metrics-interfaces.js +6 -0
  19. package/dist/metrics/metrics-interfaces.js.map +1 -0
  20. package/dist/metrics/open-telemetry/OpenTelemetryMetricsFactory.d.ts +10 -0
  21. package/dist/metrics/open-telemetry/OpenTelemetryMetricsFactory.js +51 -0
  22. package/dist/metrics/open-telemetry/OpenTelemetryMetricsFactory.js.map +1 -0
  23. package/dist/metrics/open-telemetry/util.d.ts +6 -0
  24. package/dist/metrics/open-telemetry/util.js +62 -0
  25. package/dist/metrics/open-telemetry/util.js.map +1 -0
  26. package/dist/metrics/register-metrics.d.ts +11 -0
  27. package/dist/metrics/register-metrics.js +44 -0
  28. package/dist/metrics/register-metrics.js.map +1 -0
  29. package/dist/replication/AbstractReplicationJob.d.ts +2 -0
  30. package/dist/replication/AbstractReplicationJob.js.map +1 -1
  31. package/dist/replication/AbstractReplicator.d.ts +3 -0
  32. package/dist/replication/AbstractReplicator.js +3 -0
  33. package/dist/replication/AbstractReplicator.js.map +1 -1
  34. package/dist/replication/ReplicationModule.d.ts +7 -0
  35. package/dist/replication/ReplicationModule.js +1 -0
  36. package/dist/replication/ReplicationModule.js.map +1 -1
  37. package/dist/replication/replication-index.d.ts +1 -0
  38. package/dist/replication/replication-index.js +1 -0
  39. package/dist/replication/replication-index.js.map +1 -1
  40. package/dist/replication/replication-metrics.d.ts +11 -0
  41. package/dist/replication/replication-metrics.js +39 -0
  42. package/dist/replication/replication-metrics.js.map +1 -0
  43. package/dist/routes/endpoints/socket-route.js +5 -5
  44. package/dist/routes/endpoints/socket-route.js.map +1 -1
  45. package/dist/routes/endpoints/sync-stream.js +6 -6
  46. package/dist/routes/endpoints/sync-stream.js.map +1 -1
  47. package/dist/storage/storage-index.d.ts +1 -0
  48. package/dist/storage/storage-index.js +1 -0
  49. package/dist/storage/storage-index.js.map +1 -1
  50. package/dist/storage/storage-metrics.d.ts +4 -0
  51. package/dist/storage/storage-metrics.js +56 -0
  52. package/dist/storage/storage-metrics.js.map +1 -0
  53. package/dist/sync/RequestTracker.d.ts +3 -0
  54. package/dist/sync/RequestTracker.js +8 -3
  55. package/dist/sync/RequestTracker.js.map +1 -1
  56. package/dist/sync/sync.js +8 -1
  57. package/dist/sync/sync.js.map +1 -1
  58. package/dist/system/ServiceContext.d.ts +3 -3
  59. package/dist/system/ServiceContext.js +7 -3
  60. package/dist/system/ServiceContext.js.map +1 -1
  61. package/dist/util/config/compound-config-collector.js +1 -0
  62. package/dist/util/config/compound-config-collector.js.map +1 -1
  63. package/dist/util/config/types.d.ts +1 -0
  64. package/dist/util/env.d.ts +0 -1
  65. package/dist/util/env.js +0 -4
  66. package/dist/util/env.js.map +1 -1
  67. package/package.json +7 -7
  68. package/src/api/api-index.ts +1 -0
  69. package/src/api/api-metrics.ts +35 -0
  70. package/src/index.ts +2 -2
  71. package/src/metrics/MetricsEngine.ts +98 -0
  72. package/src/metrics/metrics-index.ts +5 -0
  73. package/src/metrics/metrics-interfaces.ts +41 -0
  74. package/src/metrics/open-telemetry/OpenTelemetryMetricsFactory.ts +66 -0
  75. package/src/metrics/open-telemetry/util.ts +80 -0
  76. package/src/metrics/register-metrics.ts +56 -0
  77. package/src/replication/AbstractReplicationJob.ts +2 -0
  78. package/src/replication/AbstractReplicator.ts +7 -0
  79. package/src/replication/ReplicationModule.ts +10 -0
  80. package/src/replication/replication-index.ts +1 -0
  81. package/src/replication/replication-metrics.ts +45 -0
  82. package/src/routes/endpoints/socket-route.ts +6 -5
  83. package/src/routes/endpoints/sync-stream.ts +7 -6
  84. package/src/storage/storage-index.ts +1 -0
  85. package/src/storage/storage-metrics.ts +67 -0
  86. package/src/sync/RequestTracker.ts +9 -3
  87. package/src/sync/sync.ts +8 -1
  88. package/src/system/ServiceContext.ts +9 -4
  89. package/src/util/config/compound-config-collector.ts +1 -0
  90. package/src/util/config/types.ts +1 -0
  91. package/src/util/env.ts +0 -4
  92. package/tsconfig.tsbuildinfo +1 -1
  93. package/dist/metrics/Metrics.d.ts +0 -30
  94. package/dist/metrics/Metrics.js +0 -202
  95. package/dist/metrics/Metrics.js.map +0 -1
  96. package/src/metrics/Metrics.ts +0 -255
@@ -0,0 +1,67 @@
1
+ import { MetricsEngine } from '../metrics/MetricsEngine.js';
2
+ import { logger } from '@powersync/lib-services-framework';
3
+ import { BucketStorageFactory, StorageMetrics } from './BucketStorageFactory.js';
4
+ import { StorageMetric } from '@powersync/service-types';
5
+
6
+ export function createCoreStorageMetrics(engine: MetricsEngine): void {
7
+ engine.createObservableGauge({
8
+ name: StorageMetric.REPLICATION_SIZE_BYTES,
9
+ description: 'Size of current data stored in PowerSync',
10
+ unit: 'bytes'
11
+ });
12
+
13
+ engine.createObservableGauge({
14
+ name: StorageMetric.OPERATION_SIZE_BYTES,
15
+ description: 'Size of operations stored in PowerSync',
16
+ unit: 'bytes'
17
+ });
18
+
19
+ engine.createObservableGauge({
20
+ name: StorageMetric.PARAMETER_SIZE_BYTES,
21
+ description: 'Size of parameter data stored in PowerSync',
22
+ unit: 'bytes'
23
+ });
24
+ }
25
+
26
+ export function initializeCoreStorageMetrics(engine: MetricsEngine, storage: BucketStorageFactory): void {
27
+ const replication_storage_size_bytes = engine.getObservableGauge(StorageMetric.REPLICATION_SIZE_BYTES);
28
+ const operation_storage_size_bytes = engine.getObservableGauge(StorageMetric.OPERATION_SIZE_BYTES);
29
+ const parameter_storage_size_bytes = engine.getObservableGauge(StorageMetric.PARAMETER_SIZE_BYTES);
30
+
31
+ const MINIMUM_INTERVAL = 60_000;
32
+
33
+ let cachedRequest: Promise<StorageMetrics | null> | undefined = undefined;
34
+ let cacheTimestamp = 0;
35
+
36
+ const getMetrics = () => {
37
+ if (cachedRequest == null || Date.now() - cacheTimestamp > MINIMUM_INTERVAL) {
38
+ cachedRequest = storage.getStorageMetrics().catch((e) => {
39
+ logger.error(`Failed to get storage metrics`, e);
40
+ return null;
41
+ });
42
+ cacheTimestamp = Date.now();
43
+ }
44
+ return cachedRequest;
45
+ };
46
+
47
+ replication_storage_size_bytes.setValueProvider(async () => {
48
+ const metrics = await getMetrics();
49
+ if (metrics) {
50
+ return metrics.replication_size_bytes;
51
+ }
52
+ });
53
+
54
+ operation_storage_size_bytes.setValueProvider(async () => {
55
+ const metrics = await getMetrics();
56
+ if (metrics) {
57
+ return metrics.operations_size_bytes;
58
+ }
59
+ });
60
+
61
+ parameter_storage_size_bytes.setValueProvider(async () => {
62
+ const metrics = await getMetrics();
63
+ if (metrics) {
64
+ return metrics.parameters_size_bytes;
65
+ }
66
+ });
67
+ }
@@ -1,4 +1,6 @@
1
- import { Metrics } from '../metrics/Metrics.js';
1
+ import { MetricsEngine } from '../metrics/MetricsEngine.js';
2
+
3
+ import { APIMetric } from '@powersync/service-types';
2
4
 
3
5
  /**
4
6
  * Record sync stats per request stream.
@@ -7,15 +9,19 @@ export class RequestTracker {
7
9
  operationsSynced = 0;
8
10
  dataSyncedBytes = 0;
9
11
 
12
+ constructor(private metrics: MetricsEngine) {
13
+ this.metrics = metrics;
14
+ }
15
+
10
16
  addOperationsSynced(operations: number) {
11
17
  this.operationsSynced += operations;
12
18
 
13
- Metrics.getInstance().operations_synced_total.add(operations);
19
+ this.metrics.getCounter(APIMetric.OPERATIONS_SYNCED).add(operations);
14
20
  }
15
21
 
16
22
  addDataSynced(bytes: number) {
17
23
  this.dataSyncedBytes += bytes;
18
24
 
19
- Metrics.getInstance().data_synced_bytes.add(bytes);
25
+ this.metrics.getCounter(APIMetric.DATA_SYNCED_BYTES).add(bytes);
20
26
  }
21
27
  }
package/src/sync/sync.ts CHANGED
@@ -180,7 +180,14 @@ async function* streamResponseInner(
180
180
  function markOperationsSent(operations: number) {
181
181
  syncedOperations += operations;
182
182
  tracker.addOperationsSynced(operations);
183
- maybeRaceForNewCheckpoint();
183
+ // Disable interrupting checkpoints for now.
184
+ // There is a bug with interrupting checkpoints where:
185
+ // 1. User is in the middle of syncing a large batch of data (for example initial sync).
186
+ // 2. A new checkpoint comes in, which interrupts the batch.
187
+ // 3. However, the new checkpoint does not contain any new data for this connection, so nothing further is synced.
188
+ // This then causes the client to wait indefinitely for the remaining data or checkpoint_complete message. That is
189
+ // only resolved when a new checkpoint comes in that does have data for this connection, or the connection is restarted.
190
+ // maybeRaceForNewCheckpoint();
184
191
  }
185
192
 
186
193
  // This incrementally updates dataBuckets with each individual bucket position.
@@ -1,7 +1,7 @@
1
1
  import { LifeCycledSystem, MigrationManager, ServiceIdentifier, container } from '@powersync/lib-services-framework';
2
2
 
3
3
  import { framework } from '../index.js';
4
- import * as metrics from '../metrics/Metrics.js';
4
+ import * as metrics from '../metrics/MetricsEngine.js';
5
5
  import { PowerSyncMigrationManager } from '../migrations/PowerSyncMigrationManager.js';
6
6
  import * as replication from '../replication/replication-index.js';
7
7
  import * as routes from '../routes/routes-index.js';
@@ -12,7 +12,7 @@ import { SyncContext } from '../sync/SyncContext.js';
12
12
  export interface ServiceContext {
13
13
  configuration: utils.ResolvedPowerSyncConfig;
14
14
  lifeCycleEngine: LifeCycledSystem;
15
- metrics: metrics.Metrics | null;
15
+ metricsEngine: metrics.MetricsEngine;
16
16
  replicationEngine: replication.ReplicationEngine | null;
17
17
  routerEngine: routes.RouterEngine | null;
18
18
  storageEngine: storage.StorageEngine;
@@ -37,6 +37,11 @@ export class ServiceContextContainer implements ServiceContext {
37
37
  configuration
38
38
  });
39
39
 
40
+ this.lifeCycleEngine.withLifecycle(this.storageEngine, {
41
+ start: (storageEngine) => storageEngine.start(),
42
+ stop: (storageEngine) => storageEngine.shutDown()
43
+ });
44
+
40
45
  this.syncContext = new SyncContext({
41
46
  maxDataFetchConcurrency: configuration.api_parameters.max_data_fetch_concurrency,
42
47
  maxBuckets: configuration.api_parameters.max_buckets_per_connection,
@@ -65,8 +70,8 @@ export class ServiceContextContainer implements ServiceContext {
65
70
  return container.getOptional(routes.RouterEngine);
66
71
  }
67
72
 
68
- get metrics(): metrics.Metrics | null {
69
- return container.getOptional(metrics.Metrics);
73
+ get metricsEngine(): metrics.MetricsEngine {
74
+ return container.getImplementation(metrics.MetricsEngine);
70
75
  }
71
76
 
72
77
  get migrations(): PowerSyncMigrationManager {
@@ -154,6 +154,7 @@ export class CompoundConfigCollector {
154
154
  metadata: baseConfig.metadata ?? {},
155
155
  migrations: baseConfig.migrations,
156
156
  telemetry: {
157
+ prometheus_port: baseConfig.telemetry?.prometheus_port,
157
158
  disable_telemetry_sharing: baseConfig.telemetry?.disable_telemetry_sharing ?? false,
158
159
  internal_service_endpoint:
159
160
  baseConfig.telemetry?.internal_service_endpoint ?? 'https://pulse.journeyapps.com/v1/metrics'
@@ -55,6 +55,7 @@ export type ResolvedPowerSyncConfig = {
55
55
  };
56
56
 
57
57
  telemetry: {
58
+ prometheus_port?: number;
58
59
  disable_telemetry_sharing: boolean;
59
60
  internal_service_endpoint: string;
60
61
  };
package/src/util/env.ts CHANGED
@@ -19,10 +19,6 @@ export const env = utils.collectEnvironmentVariables({
19
19
  * Runner to be started in this process
20
20
  */
21
21
  PS_RUNNER_TYPE: utils.type.string.default(ServiceRunner.UNIFIED),
22
- /**
23
- * Port for metrics
24
- */
25
- METRICS_PORT: utils.type.number.optional(),
26
22
 
27
23
  NODE_ENV: utils.type.string.optional()
28
24
  });