@powersync/service-core 0.0.2 → 0.1.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 (53) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/index.d.ts +2 -2
  3. package/dist/index.js +2 -2
  4. package/dist/metrics/Metrics.d.ts +30 -0
  5. package/dist/metrics/Metrics.js +176 -0
  6. package/dist/metrics/Metrics.js.map +1 -0
  7. package/dist/migrations/migrations.js +2 -2
  8. package/dist/migrations/migrations.js.map +1 -1
  9. package/dist/replication/WalStream.js +7 -7
  10. package/dist/replication/WalStream.js.map +1 -1
  11. package/dist/routes/socket-route.js +4 -4
  12. package/dist/routes/socket-route.js.map +1 -1
  13. package/dist/routes/sync-stream.js +3 -3
  14. package/dist/routes/sync-stream.js.map +1 -1
  15. package/dist/storage/BucketStorage.d.ts +4 -0
  16. package/dist/storage/BucketStorage.js.map +1 -1
  17. package/dist/storage/MongoBucketStorage.d.ts +1 -0
  18. package/dist/storage/MongoBucketStorage.js +21 -0
  19. package/dist/storage/MongoBucketStorage.js.map +1 -1
  20. package/dist/storage/mongo/db.d.ts +4 -1
  21. package/dist/storage/mongo/db.js +4 -0
  22. package/dist/storage/mongo/db.js.map +1 -1
  23. package/dist/storage/mongo/models.d.ts +3 -0
  24. package/dist/sync/sync.js +2 -2
  25. package/dist/sync/sync.js.map +1 -1
  26. package/dist/sync/util.js +2 -2
  27. package/dist/sync/util.js.map +1 -1
  28. package/dist/util/config/compound-config-collector.js +4 -0
  29. package/dist/util/config/compound-config-collector.js.map +1 -1
  30. package/dist/util/config/types.d.ts +4 -0
  31. package/package.json +10 -10
  32. package/src/index.ts +2 -2
  33. package/src/metrics/Metrics.ts +263 -0
  34. package/src/migrations/migrations.ts +3 -3
  35. package/src/replication/WalStream.ts +7 -7
  36. package/src/routes/socket-route.ts +4 -4
  37. package/src/routes/sync-stream.ts +3 -3
  38. package/src/storage/BucketStorage.ts +5 -0
  39. package/src/storage/MongoBucketStorage.ts +26 -0
  40. package/src/storage/mongo/db.ts +8 -0
  41. package/src/storage/mongo/models.ts +5 -0
  42. package/src/sync/sync.ts +2 -2
  43. package/src/sync/util.ts +2 -2
  44. package/src/util/config/compound-config-collector.ts +4 -0
  45. package/src/util/config/types.ts +6 -0
  46. package/test/src/util.ts +9 -0
  47. package/test/src/wal_stream.test.ts +23 -14
  48. package/tsconfig.json +12 -0
  49. package/tsconfig.tsbuildinfo +1 -1
  50. package/dist/metrics/metrics.d.ts +0 -16
  51. package/dist/metrics/metrics.js +0 -139
  52. package/dist/metrics/metrics.js.map +0 -1
  53. package/src/metrics/metrics.ts +0 -169
@@ -1,16 +0,0 @@
1
- import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
2
- import { CorePowerSyncSystem } from '../system/CorePowerSyncSystem.js';
3
- export declare const exporter: PrometheusExporter;
4
- export declare const data_replicated_bytes: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
5
- export declare const data_synced_bytes: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
6
- export declare const rows_replicated_total: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
7
- export declare const transactions_replicated_total: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
8
- export declare const chunks_replicated_total: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
9
- export declare const operations_synced_total: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
10
- export declare const replication_storage_size_bytes: import("@opentelemetry/api").ObservableGauge<import("@opentelemetry/api").Attributes>;
11
- export declare const operation_storage_size_bytes: import("@opentelemetry/api").ObservableGauge<import("@opentelemetry/api").Attributes>;
12
- export declare const parameter_storage_size_bytes: import("@opentelemetry/api").ObservableGauge<import("@opentelemetry/api").Attributes>;
13
- export declare const concurrent_connections: import("@opentelemetry/api").UpDownCounter<import("@opentelemetry/api").Attributes>;
14
- export declare function configureApiMetrics(): void;
15
- export declare function configureReplicationMetrics(system: CorePowerSyncSystem): void;
16
- export declare function getMetricValueForTests(name: string): Promise<number | undefined>;
@@ -1,139 +0,0 @@
1
- import * as micro from '@journeyapps-platform/micro';
2
- import { ValueType } from '@opentelemetry/api';
3
- import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
4
- import { MeterProvider } from '@opentelemetry/sdk-metrics';
5
- import * as jpgwire from '@powersync/service-jpgwire';
6
- import * as util from '../util/util-index.js';
7
- const meterProvider = new MeterProvider();
8
- const port = util.env.METRICS_PORT ?? 0;
9
- // Expose a pull-based metrics exporter on a prometheus endpoint.
10
- // This is not quite the standard approach of opentelemetry or journey-micro.
11
- // However, it avoids the need for running a separate sidecar that uses additional resources.
12
- // We can consider switching to the standard push-based architecture if needed later.
13
- export const exporter = new PrometheusExporter({ port: port, preventServerStart: true });
14
- meterProvider.addMetricReader(exporter);
15
- if (port > 0) {
16
- exporter.startServer();
17
- }
18
- const meter = meterProvider.getMeter('powersync');
19
- // 1. Data processing / month
20
- // 1a. Postgres -> PowerSync
21
- // Record on replication pod
22
- export const data_replicated_bytes = meter.createCounter('powersync_data_replicated_bytes_total', {
23
- description: 'Uncompressed size of replicated data',
24
- unit: 'bytes',
25
- valueType: ValueType.INT
26
- });
27
- // 1b. PowerSync -> clients
28
- // Record on API pod
29
- export const data_synced_bytes = meter.createCounter('powersync_data_synced_bytes_total', {
30
- description: 'Uncompressed size of synced data',
31
- unit: 'bytes',
32
- valueType: ValueType.INT
33
- });
34
- // Unused for pricing
35
- // Record on replication pod
36
- export const rows_replicated_total = meter.createCounter('powersync_rows_replicated_total', {
37
- description: 'Total number of replicated rows',
38
- valueType: ValueType.INT
39
- });
40
- // Unused for pricing
41
- // Record on replication pod
42
- export const transactions_replicated_total = meter.createCounter('powersync_transactions_replicated_total', {
43
- description: 'Total number of replicated transactions',
44
- valueType: ValueType.INT
45
- });
46
- // Unused for pricing
47
- // Record on replication pod
48
- export const chunks_replicated_total = meter.createCounter('powersync_chunks_replicated_total', {
49
- description: 'Total number of replication chunks',
50
- valueType: ValueType.INT
51
- });
52
- // 2. Sync operations / month
53
- // Record on API pod
54
- export const operations_synced_total = meter.createCounter('powersync_operations_synced_total', {
55
- description: 'Number of operations synced',
56
- valueType: ValueType.INT
57
- });
58
- // 3. Data hosted on PowerSync sync service
59
- // Record on replication pod
60
- // 3a. Replication storage -> raw data as received from Postgres.
61
- export const replication_storage_size_bytes = meter.createObservableGauge('powersync_replication_storage_size_bytes', {
62
- description: 'Size of current data stored in PowerSync',
63
- unit: 'bytes',
64
- valueType: ValueType.INT
65
- });
66
- // 3b. Operations storage -> transformed history, as will be synced to clients
67
- export const operation_storage_size_bytes = meter.createObservableGauge('powersync_operation_storage_size_bytes', {
68
- description: 'Size of operations stored in PowerSync',
69
- unit: 'bytes',
70
- valueType: ValueType.INT
71
- });
72
- // 3c. Parameter storage -> used for parameter queries
73
- export const parameter_storage_size_bytes = meter.createObservableGauge('powersync_parameter_storage_size_bytes', {
74
- description: 'Size of parameter data stored in PowerSync',
75
- unit: 'bytes',
76
- valueType: ValueType.INT
77
- });
78
- // 4. Peak concurrent connections
79
- // Record on API pod
80
- export const concurrent_connections = meter.createUpDownCounter('powersync_concurrent_connections', {
81
- description: 'Number of concurrent sync connections',
82
- valueType: ValueType.INT
83
- });
84
- export function configureApiMetrics() {
85
- // Initialize the metric, so that it reports a value before connections
86
- // have been opened.
87
- concurrent_connections.add(0);
88
- }
89
- export function configureReplicationMetrics(system) {
90
- // Rate limit collection of these stats, since it may be an expensive query
91
- const MINIMUM_INTERVAL = 60000;
92
- let cachedRequest = undefined;
93
- let cacheTimestamp = 0;
94
- function getMetrics() {
95
- if (cachedRequest == null || Date.now() - cacheTimestamp > MINIMUM_INTERVAL) {
96
- cachedRequest = system.storage.getStorageMetrics().catch((e) => {
97
- micro.logger.error(`Failed to get storage metrics`, e);
98
- return null;
99
- });
100
- cacheTimestamp = Date.now();
101
- }
102
- return cachedRequest;
103
- }
104
- operation_storage_size_bytes.addCallback(async (result) => {
105
- const metrics = await getMetrics();
106
- if (metrics) {
107
- result.observe(metrics.operations_size_bytes);
108
- }
109
- });
110
- parameter_storage_size_bytes.addCallback(async (result) => {
111
- const metrics = await getMetrics();
112
- if (metrics) {
113
- result.observe(metrics.parameters_size_bytes);
114
- }
115
- });
116
- replication_storage_size_bytes.addCallback(async (result) => {
117
- const metrics = await getMetrics();
118
- if (metrics) {
119
- result.observe(metrics.replication_size_bytes);
120
- }
121
- });
122
- // Record replicated bytes using global jpgwire metrics.
123
- jpgwire.setMetricsRecorder({
124
- addBytesRead(bytes) {
125
- data_replicated_bytes.add(bytes);
126
- }
127
- });
128
- }
129
- export async function getMetricValueForTests(name) {
130
- const metrics = await exporter.collect();
131
- const scoped = metrics.resourceMetrics.scopeMetrics[0].metrics;
132
- const metric = scoped.find((metric) => metric.descriptor.name == name);
133
- if (metric == null) {
134
- throw new Error(`Cannot find metric ${name}. Options: ${scoped.map((metric) => metric.descriptor.name).join(',')}`);
135
- }
136
- const point = metric.dataPoints[metric.dataPoints.length - 1];
137
- return point?.value;
138
- }
139
- //# sourceMappingURL=metrics.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/metrics/metrics.ts"],"names":[],"mappings":"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"}
@@ -1,169 +0,0 @@
1
- import * as micro from '@journeyapps-platform/micro';
2
- import { ValueType } from '@opentelemetry/api';
3
- import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
4
- import { MeterProvider } from '@opentelemetry/sdk-metrics';
5
- import * as jpgwire from '@powersync/service-jpgwire';
6
-
7
- import * as util from '@/util/util-index.js';
8
- import * as storage from '@/storage/storage-index.js';
9
- import { CorePowerSyncSystem } from '../system/CorePowerSyncSystem.js';
10
-
11
- const meterProvider = new MeterProvider();
12
-
13
- const port: number = util.env.METRICS_PORT ?? 0;
14
-
15
- // Expose a pull-based metrics exporter on a prometheus endpoint.
16
- // This is not quite the standard approach of opentelemetry or journey-micro.
17
- // However, it avoids the need for running a separate sidecar that uses additional resources.
18
- // We can consider switching to the standard push-based architecture if needed later.
19
-
20
- export const exporter = new PrometheusExporter({ port: port, preventServerStart: true });
21
- meterProvider.addMetricReader(exporter);
22
-
23
- if (port > 0) {
24
- exporter.startServer();
25
- }
26
-
27
- const meter = meterProvider.getMeter('powersync');
28
-
29
- // 1. Data processing / month
30
-
31
- // 1a. Postgres -> PowerSync
32
- // Record on replication pod
33
- export const data_replicated_bytes = meter.createCounter('powersync_data_replicated_bytes_total', {
34
- description: 'Uncompressed size of replicated data',
35
- unit: 'bytes',
36
- valueType: ValueType.INT
37
- });
38
-
39
- // 1b. PowerSync -> clients
40
- // Record on API pod
41
- export const data_synced_bytes = meter.createCounter('powersync_data_synced_bytes_total', {
42
- description: 'Uncompressed size of synced data',
43
- unit: 'bytes',
44
- valueType: ValueType.INT
45
- });
46
-
47
- // Unused for pricing
48
- // Record on replication pod
49
- export const rows_replicated_total = meter.createCounter('powersync_rows_replicated_total', {
50
- description: 'Total number of replicated rows',
51
- valueType: ValueType.INT
52
- });
53
-
54
- // Unused for pricing
55
- // Record on replication pod
56
- export const transactions_replicated_total = meter.createCounter('powersync_transactions_replicated_total', {
57
- description: 'Total number of replicated transactions',
58
- valueType: ValueType.INT
59
- });
60
-
61
- // Unused for pricing
62
- // Record on replication pod
63
- export const chunks_replicated_total = meter.createCounter('powersync_chunks_replicated_total', {
64
- description: 'Total number of replication chunks',
65
- valueType: ValueType.INT
66
- });
67
-
68
- // 2. Sync operations / month
69
- // Record on API pod
70
- export const operations_synced_total = meter.createCounter('powersync_operations_synced_total', {
71
- description: 'Number of operations synced',
72
- valueType: ValueType.INT
73
- });
74
-
75
- // 3. Data hosted on PowerSync sync service
76
- // Record on replication pod
77
-
78
- // 3a. Replication storage -> raw data as received from Postgres.
79
- export const replication_storage_size_bytes = meter.createObservableGauge('powersync_replication_storage_size_bytes', {
80
- description: 'Size of current data stored in PowerSync',
81
- unit: 'bytes',
82
- valueType: ValueType.INT
83
- });
84
-
85
- // 3b. Operations storage -> transformed history, as will be synced to clients
86
- export const operation_storage_size_bytes = meter.createObservableGauge('powersync_operation_storage_size_bytes', {
87
- description: 'Size of operations stored in PowerSync',
88
- unit: 'bytes',
89
- valueType: ValueType.INT
90
- });
91
-
92
- // 3c. Parameter storage -> used for parameter queries
93
- export const parameter_storage_size_bytes = meter.createObservableGauge('powersync_parameter_storage_size_bytes', {
94
- description: 'Size of parameter data stored in PowerSync',
95
- unit: 'bytes',
96
- valueType: ValueType.INT
97
- });
98
-
99
- // 4. Peak concurrent connections
100
- // Record on API pod
101
-
102
- export const concurrent_connections = meter.createUpDownCounter('powersync_concurrent_connections', {
103
- description: 'Number of concurrent sync connections',
104
- valueType: ValueType.INT
105
- });
106
-
107
- export function configureApiMetrics() {
108
- // Initialize the metric, so that it reports a value before connections
109
- // have been opened.
110
- concurrent_connections.add(0);
111
- }
112
-
113
- export function configureReplicationMetrics(system: CorePowerSyncSystem) {
114
- // Rate limit collection of these stats, since it may be an expensive query
115
- const MINIMUM_INTERVAL = 60_000;
116
-
117
- let cachedRequest: Promise<storage.StorageMetrics | null> | undefined = undefined;
118
- let cacheTimestamp = 0;
119
-
120
- function getMetrics() {
121
- if (cachedRequest == null || Date.now() - cacheTimestamp > MINIMUM_INTERVAL) {
122
- cachedRequest = system.storage.getStorageMetrics().catch((e) => {
123
- micro.logger.error(`Failed to get storage metrics`, e);
124
- return null;
125
- });
126
- cacheTimestamp = Date.now();
127
- }
128
- return cachedRequest;
129
- }
130
-
131
- operation_storage_size_bytes.addCallback(async (result) => {
132
- const metrics = await getMetrics();
133
- if (metrics) {
134
- result.observe(metrics.operations_size_bytes);
135
- }
136
- });
137
-
138
- parameter_storage_size_bytes.addCallback(async (result) => {
139
- const metrics = await getMetrics();
140
- if (metrics) {
141
- result.observe(metrics.parameters_size_bytes);
142
- }
143
- });
144
-
145
- replication_storage_size_bytes.addCallback(async (result) => {
146
- const metrics = await getMetrics();
147
- if (metrics) {
148
- result.observe(metrics.replication_size_bytes);
149
- }
150
- });
151
-
152
- // Record replicated bytes using global jpgwire metrics.
153
- jpgwire.setMetricsRecorder({
154
- addBytesRead(bytes) {
155
- data_replicated_bytes.add(bytes);
156
- }
157
- });
158
- }
159
-
160
- export async function getMetricValueForTests(name: string): Promise<number | undefined> {
161
- const metrics = await exporter.collect();
162
- const scoped = metrics.resourceMetrics.scopeMetrics[0].metrics;
163
- const metric = scoped.find((metric) => metric.descriptor.name == name);
164
- if (metric == null) {
165
- throw new Error(`Cannot find metric ${name}. Options: ${scoped.map((metric) => metric.descriptor.name).join(',')}`);
166
- }
167
- const point = metric.dataPoints[metric.dataPoints.length - 1];
168
- return point?.value as number;
169
- }