@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.
- package/CHANGELOG.md +12 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/metrics/Metrics.d.ts +30 -0
- package/dist/metrics/Metrics.js +176 -0
- package/dist/metrics/Metrics.js.map +1 -0
- package/dist/migrations/migrations.js +2 -2
- package/dist/migrations/migrations.js.map +1 -1
- package/dist/replication/WalStream.js +7 -7
- package/dist/replication/WalStream.js.map +1 -1
- package/dist/routes/socket-route.js +4 -4
- package/dist/routes/socket-route.js.map +1 -1
- package/dist/routes/sync-stream.js +3 -3
- package/dist/routes/sync-stream.js.map +1 -1
- package/dist/storage/BucketStorage.d.ts +4 -0
- package/dist/storage/BucketStorage.js.map +1 -1
- package/dist/storage/MongoBucketStorage.d.ts +1 -0
- package/dist/storage/MongoBucketStorage.js +21 -0
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/mongo/db.d.ts +4 -1
- package/dist/storage/mongo/db.js +4 -0
- package/dist/storage/mongo/db.js.map +1 -1
- package/dist/storage/mongo/models.d.ts +3 -0
- package/dist/sync/sync.js +2 -2
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/util.js +2 -2
- package/dist/sync/util.js.map +1 -1
- package/dist/util/config/compound-config-collector.js +4 -0
- package/dist/util/config/compound-config-collector.js.map +1 -1
- package/dist/util/config/types.d.ts +4 -0
- package/package.json +10 -10
- package/src/index.ts +2 -2
- package/src/metrics/Metrics.ts +263 -0
- package/src/migrations/migrations.ts +3 -3
- package/src/replication/WalStream.ts +7 -7
- package/src/routes/socket-route.ts +4 -4
- package/src/routes/sync-stream.ts +3 -3
- package/src/storage/BucketStorage.ts +5 -0
- package/src/storage/MongoBucketStorage.ts +26 -0
- package/src/storage/mongo/db.ts +8 -0
- package/src/storage/mongo/models.ts +5 -0
- package/src/sync/sync.ts +2 -2
- package/src/sync/util.ts +2 -2
- package/src/util/config/compound-config-collector.ts +4 -0
- package/src/util/config/types.ts +6 -0
- package/test/src/util.ts +9 -0
- package/test/src/wal_stream.test.ts +23 -14
- package/tsconfig.json +12 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/metrics/metrics.d.ts +0 -16
- package/dist/metrics/metrics.js +0 -139
- package/dist/metrics/metrics.js.map +0 -1
- 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>;
|
package/dist/metrics/metrics.js
DELETED
|
@@ -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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"}
|
package/src/metrics/metrics.ts
DELETED
|
@@ -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
|
-
}
|