@powersync/service-core 0.0.0-dev-20250317122913 → 0.0.0-dev-20250325131118
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 +18 -4
- package/dist/api/api-index.d.ts +1 -0
- package/dist/api/api-index.js +1 -0
- package/dist/api/api-index.js.map +1 -1
- package/dist/api/api-metrics.d.ts +11 -0
- package/dist/api/api-metrics.js +30 -0
- package/dist/api/api-metrics.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/metrics/MetricsEngine.d.ts +21 -0
- package/dist/metrics/MetricsEngine.js +79 -0
- package/dist/metrics/MetricsEngine.js.map +1 -0
- package/dist/metrics/metrics-index.d.ts +4 -0
- package/dist/metrics/metrics-index.js +5 -0
- package/dist/metrics/metrics-index.js.map +1 -0
- package/dist/metrics/metrics-interfaces.d.ts +36 -0
- package/dist/metrics/metrics-interfaces.js +6 -0
- package/dist/metrics/metrics-interfaces.js.map +1 -0
- package/dist/metrics/open-telemetry/OpenTelemetryMetricsFactory.d.ts +10 -0
- package/dist/metrics/open-telemetry/OpenTelemetryMetricsFactory.js +51 -0
- package/dist/metrics/open-telemetry/OpenTelemetryMetricsFactory.js.map +1 -0
- package/dist/metrics/open-telemetry/util.d.ts +6 -0
- package/dist/metrics/open-telemetry/util.js +56 -0
- package/dist/metrics/open-telemetry/util.js.map +1 -0
- package/dist/replication/AbstractReplicationJob.d.ts +2 -0
- package/dist/replication/AbstractReplicationJob.js.map +1 -1
- package/dist/replication/AbstractReplicator.d.ts +3 -0
- package/dist/replication/AbstractReplicator.js +3 -0
- package/dist/replication/AbstractReplicator.js.map +1 -1
- package/dist/replication/ReplicationModule.d.ts +7 -0
- package/dist/replication/ReplicationModule.js +1 -0
- package/dist/replication/ReplicationModule.js.map +1 -1
- package/dist/replication/replication-index.d.ts +1 -0
- package/dist/replication/replication-index.js +1 -0
- package/dist/replication/replication-index.js.map +1 -1
- package/dist/replication/replication-metrics.d.ts +11 -0
- package/dist/replication/replication-metrics.js +39 -0
- package/dist/replication/replication-metrics.js.map +1 -0
- package/dist/routes/configure-fastify.d.ts +1 -1
- package/dist/routes/endpoints/probes.d.ts +2 -2
- package/dist/routes/endpoints/probes.js +16 -2
- package/dist/routes/endpoints/probes.js.map +1 -1
- package/dist/routes/endpoints/socket-route.js +5 -5
- package/dist/routes/endpoints/socket-route.js.map +1 -1
- package/dist/routes/endpoints/sync-stream.js +6 -6
- package/dist/routes/endpoints/sync-stream.js.map +1 -1
- package/dist/storage/SyncRulesBucketStorage.d.ts +11 -1
- package/dist/storage/SyncRulesBucketStorage.js +1 -1
- package/dist/storage/SyncRulesBucketStorage.js.map +1 -1
- package/dist/storage/WriteCheckpointAPI.d.ts +0 -2
- package/dist/storage/WriteCheckpointAPI.js.map +1 -1
- package/dist/storage/storage-index.d.ts +1 -0
- package/dist/storage/storage-index.js +1 -0
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/storage/storage-metrics.d.ts +4 -0
- package/dist/storage/storage-metrics.js +56 -0
- package/dist/storage/storage-metrics.js.map +1 -0
- package/dist/sync/BucketChecksumState.d.ts +4 -2
- package/dist/sync/BucketChecksumState.js +17 -26
- package/dist/sync/BucketChecksumState.js.map +1 -1
- package/dist/sync/RequestTracker.d.ts +3 -0
- package/dist/sync/RequestTracker.js +8 -3
- package/dist/sync/RequestTracker.js.map +1 -1
- package/dist/sync/util.d.ts +10 -2
- package/dist/sync/util.js +25 -6
- package/dist/sync/util.js.map +1 -1
- package/dist/system/ServiceContext.d.ts +3 -3
- package/dist/system/ServiceContext.js +7 -3
- package/dist/system/ServiceContext.js.map +1 -1
- package/package.json +8 -8
- package/src/api/api-index.ts +1 -0
- package/src/api/api-metrics.ts +35 -0
- package/src/index.ts +2 -2
- package/src/metrics/MetricsEngine.ts +98 -0
- package/src/metrics/metrics-index.ts +4 -0
- package/src/metrics/metrics-interfaces.ts +41 -0
- package/src/metrics/open-telemetry/OpenTelemetryMetricsFactory.ts +66 -0
- package/src/metrics/open-telemetry/util.ts +74 -0
- package/src/replication/AbstractReplicationJob.ts +2 -0
- package/src/replication/AbstractReplicator.ts +7 -0
- package/src/replication/ReplicationModule.ts +10 -0
- package/src/replication/replication-index.ts +1 -0
- package/src/replication/replication-metrics.ts +45 -0
- package/src/routes/endpoints/probes.ts +18 -2
- package/src/routes/endpoints/socket-route.ts +6 -5
- package/src/routes/endpoints/sync-stream.ts +7 -6
- package/src/storage/SyncRulesBucketStorage.ts +12 -2
- package/src/storage/WriteCheckpointAPI.ts +0 -2
- package/src/storage/storage-index.ts +1 -0
- package/src/storage/storage-metrics.ts +67 -0
- package/src/sync/BucketChecksumState.ts +25 -41
- package/src/sync/RequestTracker.ts +9 -3
- package/src/sync/util.ts +29 -8
- package/src/system/ServiceContext.ts +9 -4
- package/test/src/routes/probes.integration.test.ts +5 -5
- package/test/src/routes/probes.test.ts +5 -4
- package/test/src/sync/BucketChecksumState.test.ts +5 -5
- package/test/src/util.test.ts +48 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/metrics/Metrics.d.ts +0 -30
- package/dist/metrics/Metrics.js +0 -202
- package/dist/metrics/Metrics.js.map +0 -1
- package/src/metrics/Metrics.ts +0 -255
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { APIMetric } from '@powersync/service-types';
|
|
2
2
|
/**
|
|
3
3
|
* Record sync stats per request stream.
|
|
4
4
|
*/
|
|
5
5
|
export class RequestTracker {
|
|
6
|
+
metrics;
|
|
6
7
|
operationsSynced = 0;
|
|
7
8
|
dataSyncedBytes = 0;
|
|
9
|
+
constructor(metrics) {
|
|
10
|
+
this.metrics = metrics;
|
|
11
|
+
this.metrics = metrics;
|
|
12
|
+
}
|
|
8
13
|
addOperationsSynced(operations) {
|
|
9
14
|
this.operationsSynced += operations;
|
|
10
|
-
|
|
15
|
+
this.metrics.getCounter(APIMetric.OPERATIONS_SYNCED).add(operations);
|
|
11
16
|
}
|
|
12
17
|
addDataSynced(bytes) {
|
|
13
18
|
this.dataSyncedBytes += bytes;
|
|
14
|
-
|
|
19
|
+
this.metrics.getCounter(APIMetric.DATA_SYNCED_BYTES).add(bytes);
|
|
15
20
|
}
|
|
16
21
|
}
|
|
17
22
|
//# sourceMappingURL=RequestTracker.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestTracker.js","sourceRoot":"","sources":["../../src/sync/RequestTracker.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RequestTracker.js","sourceRoot":"","sources":["../../src/sync/RequestTracker.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD;;GAEG;AACH,MAAM,OAAO,cAAc;IAIL;IAHpB,gBAAgB,GAAG,CAAC,CAAC;IACrB,eAAe,GAAG,CAAC,CAAC;IAEpB,YAAoB,OAAsB;QAAtB,YAAO,GAAP,OAAO,CAAe;QACxC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,mBAAmB,CAAC,UAAkB;QACpC,IAAI,CAAC,gBAAgB,IAAI,UAAU,CAAC;QAEpC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACvE,CAAC;IAED,aAAa,CAAC,KAAa;QACzB,IAAI,CAAC,eAAe,IAAI,KAAK,CAAC;QAE9B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClE,CAAC;CACF"}
|
package/dist/sync/util.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { SemaphoreInterface } from 'async-mutex';
|
|
1
2
|
import * as util from '../util/util-index.js';
|
|
2
3
|
import { RequestTracker } from './RequestTracker.js';
|
|
3
|
-
import { SemaphoreInterface } from 'async-mutex';
|
|
4
4
|
export type TokenStreamOptions = {
|
|
5
5
|
/**
|
|
6
6
|
* Adds periodic keepalive events
|
|
@@ -32,4 +32,12 @@ export declare function acquireSemaphoreAbortable(semaphone: SemaphoreInterface,
|
|
|
32
32
|
* if it is not specifically handled.
|
|
33
33
|
*/
|
|
34
34
|
export declare function settledPromise<T>(promise: Promise<T>): Promise<PromiseSettledResult<T>>;
|
|
35
|
-
export
|
|
35
|
+
export type MapOrSet<T> = Map<T, any> | Set<T>;
|
|
36
|
+
/**
|
|
37
|
+
* Check if two sets have any element(s) in common.
|
|
38
|
+
*/
|
|
39
|
+
export declare function hasIntersection<T>(a: MapOrSet<T>, b: MapOrSet<T>): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Return the intersection of two sets or maps.
|
|
42
|
+
*/
|
|
43
|
+
export declare function getIntersection<T>(a: MapOrSet<T>, b: MapOrSet<T>): IterableIterator<T>;
|
package/dist/sync/util.js
CHANGED
|
@@ -113,14 +113,33 @@ export function settledPromise(promise) {
|
|
|
113
113
|
};
|
|
114
114
|
});
|
|
115
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Check if two sets have any element(s) in common.
|
|
118
|
+
*/
|
|
116
119
|
export function hasIntersection(a, b) {
|
|
117
|
-
|
|
118
|
-
|
|
120
|
+
for (let _ of getIntersection(a, b)) {
|
|
121
|
+
return true;
|
|
119
122
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Return the intersection of two sets or maps.
|
|
127
|
+
*/
|
|
128
|
+
export function* getIntersection(a, b) {
|
|
129
|
+
// Iterate over the smaller set to reduce the number of lookups
|
|
130
|
+
if (a.size < b.size) {
|
|
131
|
+
for (let key of a.keys()) {
|
|
132
|
+
if (b.has(key)) {
|
|
133
|
+
yield key;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
for (let key of b.keys()) {
|
|
140
|
+
if (a.has(key)) {
|
|
141
|
+
yield key;
|
|
142
|
+
}
|
|
124
143
|
}
|
|
125
144
|
}
|
|
126
145
|
}
|
package/dist/sync/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/sync/util.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/sync/util.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LifeCycledSystem, ServiceIdentifier } from '@powersync/lib-services-framework';
|
|
2
|
-
import * as metrics from '../metrics/
|
|
2
|
+
import * as metrics from '../metrics/MetricsEngine.js';
|
|
3
3
|
import { PowerSyncMigrationManager } from '../migrations/PowerSyncMigrationManager.js';
|
|
4
4
|
import * as replication from '../replication/replication-index.js';
|
|
5
5
|
import * as routes from '../routes/routes-index.js';
|
|
@@ -9,7 +9,7 @@ import { SyncContext } from '../sync/SyncContext.js';
|
|
|
9
9
|
export interface ServiceContext {
|
|
10
10
|
configuration: utils.ResolvedPowerSyncConfig;
|
|
11
11
|
lifeCycleEngine: LifeCycledSystem;
|
|
12
|
-
|
|
12
|
+
metricsEngine: metrics.MetricsEngine;
|
|
13
13
|
replicationEngine: replication.ReplicationEngine | null;
|
|
14
14
|
routerEngine: routes.RouterEngine | null;
|
|
15
15
|
storageEngine: storage.StorageEngine;
|
|
@@ -29,7 +29,7 @@ export declare class ServiceContextContainer implements ServiceContext {
|
|
|
29
29
|
constructor(configuration: utils.ResolvedPowerSyncConfig);
|
|
30
30
|
get replicationEngine(): replication.ReplicationEngine | null;
|
|
31
31
|
get routerEngine(): routes.RouterEngine | null;
|
|
32
|
-
get
|
|
32
|
+
get metricsEngine(): metrics.MetricsEngine;
|
|
33
33
|
get migrations(): PowerSyncMigrationManager;
|
|
34
34
|
/**
|
|
35
35
|
* Allows for registering core and generic implementations of services/helpers.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LifeCycledSystem, MigrationManager, container } from '@powersync/lib-services-framework';
|
|
2
2
|
import { framework } from '../index.js';
|
|
3
|
-
import * as metrics from '../metrics/
|
|
3
|
+
import * as metrics from '../metrics/MetricsEngine.js';
|
|
4
4
|
import * as replication from '../replication/replication-index.js';
|
|
5
5
|
import * as routes from '../routes/routes-index.js';
|
|
6
6
|
import * as storage from '../storage/storage-index.js';
|
|
@@ -21,6 +21,10 @@ export class ServiceContextContainer {
|
|
|
21
21
|
this.storageEngine = new storage.StorageEngine({
|
|
22
22
|
configuration
|
|
23
23
|
});
|
|
24
|
+
this.lifeCycleEngine.withLifecycle(this.storageEngine, {
|
|
25
|
+
start: (storageEngine) => storageEngine.start(),
|
|
26
|
+
stop: (storageEngine) => storageEngine.shutDown()
|
|
27
|
+
});
|
|
24
28
|
this.syncContext = new SyncContext({
|
|
25
29
|
maxDataFetchConcurrency: configuration.api_parameters.max_data_fetch_concurrency,
|
|
26
30
|
maxBuckets: configuration.api_parameters.max_buckets_per_connection,
|
|
@@ -43,8 +47,8 @@ export class ServiceContextContainer {
|
|
|
43
47
|
get routerEngine() {
|
|
44
48
|
return container.getOptional(routes.RouterEngine);
|
|
45
49
|
}
|
|
46
|
-
get
|
|
47
|
-
return container.
|
|
50
|
+
get metricsEngine() {
|
|
51
|
+
return container.getImplementation(metrics.MetricsEngine);
|
|
48
52
|
}
|
|
49
53
|
get migrations() {
|
|
50
54
|
return container.getImplementation(framework.ContainerImplementation.MIGRATION_MANAGER);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServiceContext.js","sourceRoot":"","sources":["../../src/system/ServiceContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAqB,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAErH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,OAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"ServiceContext.js","sourceRoot":"","sources":["../../src/system/ServiceContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAqB,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAErH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,OAAO,MAAM,6BAA6B,CAAC;AAEvD,OAAO,KAAK,WAAW,MAAM,qCAAqC,CAAC;AACnE,OAAO,KAAK,MAAM,MAAM,2BAA2B,CAAC;AACpD,OAAO,KAAK,OAAO,MAAM,6BAA6B,CAAC;AAEvD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAarD;;;;GAIG;AACH,MAAM,OAAO,uBAAuB;IAKf;IAJnB,eAAe,CAAmB;IAClC,aAAa,CAAwB;IACrC,WAAW,CAAc;IAEzB,YAAmB,aAA4C;QAA5C,kBAAa,GAAb,aAAa,CAA+B;QAC7D,IAAI,CAAC,eAAe,GAAG,IAAI,gBAAgB,EAAE,CAAC;QAE9C,IAAI,CAAC,aAAa,GAAG,IAAI,OAAO,CAAC,aAAa,CAAC;YAC7C,aAAa;SACd,CAAC,CAAC;QAEH,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,IAAI,CAAC,aAAa,EAAE;YACrD,KAAK,EAAE,CAAC,aAAa,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE;YAC/C,IAAI,EAAE,CAAC,aAAa,EAAE,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE;SAClD,CAAC,CAAC;QAEH,IAAI,CAAC,WAAW,GAAG,IAAI,WAAW,CAAC;YACjC,uBAAuB,EAAE,aAAa,CAAC,cAAc,CAAC,0BAA0B;YAChF,UAAU,EAAE,aAAa,CAAC,cAAc,CAAC,0BAA0B;YACnE,wBAAwB,EAAE,aAAa,CAAC,cAAc,CAAC,2BAA2B;SACnF,CAAC,CAAC;QAEH,MAAM,gBAAgB,GAAG,IAAI,gBAAgB,EAAE,CAAC;QAChD,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,uBAAuB,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,CAAC;QAE1F,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,gBAAgB,EAAE;YACnD,yDAAyD;YACzD,KAAK,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE;SACrD,CAAC,CAAC;QAEH,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,IAAI,CAAC,aAAa,EAAE;YACrD,KAAK,EAAE,CAAC,aAAa,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE;YAC/C,IAAI,EAAE,CAAC,aAAa,EAAE,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE;SAClD,CAAC,CAAC;IACL,CAAC;IAED,IAAI,iBAAiB;QACnB,OAAO,SAAS,CAAC,WAAW,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,YAAY;QACd,OAAO,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACpD,CAAC;IAED,IAAI,aAAa;QACf,OAAO,SAAS,CAAC,iBAAiB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAC5D,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,SAAS,CAAC,iBAAiB,CAAC,SAAS,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,CAAC;IAC1F,CAAC;IAED;;;OAGG;IACH,QAAQ,CAAI,UAAgC,EAAE,cAAiB;QAC7D,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,GAAG,CAAI,UAAgC;QACrC,OAAO,SAAS,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;IACjD,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -5,17 +5,17 @@
|
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
|
-
"version": "0.0.0-dev-
|
|
8
|
+
"version": "0.0.0-dev-20250325131118",
|
|
9
9
|
"main": "dist/index.js",
|
|
10
10
|
"license": "FSL-1.1-Apache-2.0",
|
|
11
11
|
"type": "module",
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@js-sdsl/ordered-set": "^4.4.2",
|
|
14
|
-
"@opentelemetry/api": "~1.
|
|
15
|
-
"@opentelemetry/exporter-metrics-otlp-http": "^0.
|
|
16
|
-
"@opentelemetry/exporter-prometheus": "^0.
|
|
17
|
-
"@opentelemetry/resources": "^1.
|
|
18
|
-
"@opentelemetry/sdk-metrics": "1.
|
|
14
|
+
"@opentelemetry/api": "~1.9.0",
|
|
15
|
+
"@opentelemetry/exporter-metrics-otlp-http": "^0.57.2",
|
|
16
|
+
"@opentelemetry/exporter-prometheus": "^0.57.2",
|
|
17
|
+
"@opentelemetry/resources": "^1.30.1",
|
|
18
|
+
"@opentelemetry/sdk-metrics": "1.30.1",
|
|
19
19
|
"async": "^3.2.4",
|
|
20
20
|
"async-mutex": "^0.5.0",
|
|
21
21
|
"bson": "^6.10.3",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"@powersync/lib-services-framework": "0.5.3",
|
|
36
36
|
"@powersync/service-jsonbig": "0.17.10",
|
|
37
37
|
"@powersync/service-rsocket-router": "0.0.20",
|
|
38
|
-
"@powersync/service-sync-rules": "0.
|
|
39
|
-
"@powersync/service-types": "0.
|
|
38
|
+
"@powersync/service-sync-rules": "0.25.0",
|
|
39
|
+
"@powersync/service-types": "0.0.0-dev-20250325131118"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/async": "^3.2.24",
|
package/src/api/api-index.ts
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { MetricsEngine } from '../metrics/MetricsEngine.js';
|
|
2
|
+
import { APIMetric } from '@powersync/service-types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Create and register the core API metrics.
|
|
6
|
+
* @param engine
|
|
7
|
+
*/
|
|
8
|
+
export function createCoreAPIMetrics(engine: MetricsEngine): void {
|
|
9
|
+
engine.createCounter({
|
|
10
|
+
name: APIMetric.DATA_SYNCED_BYTES,
|
|
11
|
+
description: 'Uncompressed size of synced data',
|
|
12
|
+
unit: 'bytes'
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
engine.createCounter({
|
|
16
|
+
name: APIMetric.OPERATIONS_SYNCED,
|
|
17
|
+
description: 'Number of operations synced'
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
engine.createUpDownCounter({
|
|
21
|
+
name: APIMetric.CONCURRENT_CONNECTIONS,
|
|
22
|
+
description: 'Number of concurrent sync connections'
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Initialise the core API metrics. This should be called after the metrics have been created.
|
|
28
|
+
* @param engine
|
|
29
|
+
*/
|
|
30
|
+
export function initializeCoreAPIMetrics(engine: MetricsEngine): void {
|
|
31
|
+
const concurrent_connections = engine.getUpDownCounter(APIMetric.CONCURRENT_CONNECTIONS);
|
|
32
|
+
|
|
33
|
+
// Initialize the metric, so that it reports a value before connections have been opened.
|
|
34
|
+
concurrent_connections.add(0);
|
|
35
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -12,8 +12,8 @@ export * as entry from './entry/entry-index.js';
|
|
|
12
12
|
// Re-export framework for easy use of Container API
|
|
13
13
|
export * as framework from '@powersync/lib-services-framework';
|
|
14
14
|
|
|
15
|
-
export * from './metrics/
|
|
16
|
-
export * as metrics from './metrics/
|
|
15
|
+
export * from './metrics/metrics-index.js';
|
|
16
|
+
export * as metrics from './metrics/metrics-index.js';
|
|
17
17
|
|
|
18
18
|
export * from './migrations/migrations-index.js';
|
|
19
19
|
export * as migrations from './migrations/migrations-index.js';
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { logger, ServiceAssertionError } from '@powersync/lib-services-framework';
|
|
2
|
+
import { Counter, UpDownCounter, ObservableGauge, MetricMetadata, MetricsFactory } from './metrics-interfaces.js';
|
|
3
|
+
|
|
4
|
+
export interface MetricsEngineOptions {
|
|
5
|
+
factory: MetricsFactory;
|
|
6
|
+
disable_telemetry_sharing: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class MetricsEngine {
|
|
10
|
+
private counters: Map<string, Counter>;
|
|
11
|
+
private upDownCounters: Map<string, UpDownCounter>;
|
|
12
|
+
private observableGauges: Map<string, ObservableGauge>;
|
|
13
|
+
|
|
14
|
+
constructor(private options: MetricsEngineOptions) {
|
|
15
|
+
this.counters = new Map();
|
|
16
|
+
this.upDownCounters = new Map();
|
|
17
|
+
this.observableGauges = new Map();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
private get factory(): MetricsFactory {
|
|
21
|
+
return this.options.factory;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
createCounter(metadata: MetricMetadata): Counter {
|
|
25
|
+
if (this.counters.has(metadata.name)) {
|
|
26
|
+
logger.warn(`Counter with name ${metadata.name} already created and registered, skipping.`);
|
|
27
|
+
return this.counters.get(metadata.name)!;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const counter = this.factory.createCounter(metadata);
|
|
31
|
+
this.counters.set(metadata.name, counter);
|
|
32
|
+
return counter;
|
|
33
|
+
}
|
|
34
|
+
createUpDownCounter(metadata: MetricMetadata): UpDownCounter {
|
|
35
|
+
if (this.upDownCounters.has(metadata.name)) {
|
|
36
|
+
logger.warn(`UpDownCounter with name ${metadata.name} already created and registered, skipping.`);
|
|
37
|
+
return this.upDownCounters.get(metadata.name)!;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const upDownCounter = this.factory.createUpDownCounter(metadata);
|
|
41
|
+
this.upDownCounters.set(metadata.name, upDownCounter);
|
|
42
|
+
return upDownCounter;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
createObservableGauge(metadata: MetricMetadata): ObservableGauge {
|
|
46
|
+
if (this.observableGauges.has(metadata.name)) {
|
|
47
|
+
logger.warn(`ObservableGauge with name ${metadata.name} already created and registered, skipping.`);
|
|
48
|
+
return this.observableGauges.get(metadata.name)!;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const observableGauge = this.factory.createObservableGauge(metadata);
|
|
52
|
+
this.observableGauges.set(metadata.name, observableGauge);
|
|
53
|
+
return observableGauge;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
getCounter(name: string): Counter {
|
|
57
|
+
const counter = this.counters.get(name);
|
|
58
|
+
if (!counter) {
|
|
59
|
+
throw new ServiceAssertionError(`Counter '${name}' has not been created and registered yet.`);
|
|
60
|
+
}
|
|
61
|
+
return counter;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
getUpDownCounter(name: string): UpDownCounter {
|
|
65
|
+
const upDownCounter = this.upDownCounters.get(name);
|
|
66
|
+
if (!upDownCounter) {
|
|
67
|
+
throw new ServiceAssertionError(`UpDownCounter '${name}' has not been created and registered yet.`);
|
|
68
|
+
}
|
|
69
|
+
return upDownCounter;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
getObservableGauge(name: string): ObservableGauge {
|
|
73
|
+
const observableGauge = this.observableGauges.get(name);
|
|
74
|
+
if (!observableGauge) {
|
|
75
|
+
throw new ServiceAssertionError(`ObservableGauge '${name}' has not been created and registered yet.`);
|
|
76
|
+
}
|
|
77
|
+
return observableGauge;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public async start(): Promise<void> {
|
|
81
|
+
logger.info(
|
|
82
|
+
`
|
|
83
|
+
Attention:
|
|
84
|
+
PowerSync collects completely anonymous telemetry regarding usage.
|
|
85
|
+
This information is used to shape our roadmap to better serve our customers.
|
|
86
|
+
You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
|
|
87
|
+
https://docs.powersync.com/self-hosting/lifecycle-maintenance/telemetry
|
|
88
|
+
`.trim()
|
|
89
|
+
);
|
|
90
|
+
logger.info(`Anonymous telemetry is currently: ${this.options.disable_telemetry_sharing ? 'disabled' : 'enabled'}`);
|
|
91
|
+
|
|
92
|
+
logger.info('Successfully started Metrics Engine.');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public async shutdown(): Promise<void> {
|
|
96
|
+
logger.info('Successfully shut down Metrics Engine.');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export interface Counter {
|
|
2
|
+
/**
|
|
3
|
+
* Increment the counter by the given value. Only positive numbers are valid.
|
|
4
|
+
* @param value
|
|
5
|
+
*/
|
|
6
|
+
add(value: number): void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface UpDownCounter {
|
|
10
|
+
/**
|
|
11
|
+
* Increment or decrement(if negative) the counter by the given value.
|
|
12
|
+
* @param value
|
|
13
|
+
*/
|
|
14
|
+
add(value: number): void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface ObservableGauge {
|
|
18
|
+
/**
|
|
19
|
+
* Set a value provider that provides the value for the gauge at the time of observation.
|
|
20
|
+
* @param valueProvider
|
|
21
|
+
*/
|
|
22
|
+
setValueProvider(valueProvider: () => Promise<number | undefined>): void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export enum Precision {
|
|
26
|
+
INT = 'int',
|
|
27
|
+
DOUBLE = 'double'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface MetricMetadata {
|
|
31
|
+
name: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
unit?: string;
|
|
34
|
+
precision?: Precision;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface MetricsFactory {
|
|
38
|
+
createCounter(metadata: MetricMetadata): Counter;
|
|
39
|
+
createUpDownCounter(metadata: MetricMetadata): UpDownCounter;
|
|
40
|
+
createObservableGauge(metadata: MetricMetadata): ObservableGauge;
|
|
41
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Meter, ValueType } from '@opentelemetry/api';
|
|
2
|
+
import {
|
|
3
|
+
Counter,
|
|
4
|
+
ObservableGauge,
|
|
5
|
+
UpDownCounter,
|
|
6
|
+
MetricMetadata,
|
|
7
|
+
MetricsFactory,
|
|
8
|
+
Precision
|
|
9
|
+
} from '../metrics-interfaces.js';
|
|
10
|
+
|
|
11
|
+
export class OpenTelemetryMetricsFactory implements MetricsFactory {
|
|
12
|
+
private meter: Meter;
|
|
13
|
+
|
|
14
|
+
constructor(meter: Meter) {
|
|
15
|
+
this.meter = meter;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
createCounter(metadata: MetricMetadata): Counter {
|
|
19
|
+
return this.meter.createCounter(metadata.name, {
|
|
20
|
+
description: metadata.description,
|
|
21
|
+
unit: metadata.unit,
|
|
22
|
+
valueType: this.toValueType(metadata.precision)
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
createObservableGauge(metadata: MetricMetadata): ObservableGauge {
|
|
27
|
+
const gauge = this.meter.createObservableGauge(metadata.name, {
|
|
28
|
+
description: metadata.description,
|
|
29
|
+
unit: metadata.unit,
|
|
30
|
+
valueType: this.toValueType(metadata.precision)
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
setValueProvider(valueProvider: () => Promise<number | undefined>) {
|
|
35
|
+
gauge.addCallback(async (result) => {
|
|
36
|
+
const value = await valueProvider();
|
|
37
|
+
|
|
38
|
+
if (value) {
|
|
39
|
+
result.observe(value);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
createUpDownCounter(metadata: MetricMetadata): UpDownCounter {
|
|
47
|
+
return this.meter.createUpDownCounter(metadata.name, {
|
|
48
|
+
description: metadata.description,
|
|
49
|
+
unit: metadata.unit,
|
|
50
|
+
valueType: this.toValueType(metadata.precision)
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private toValueType(precision?: Precision): ValueType {
|
|
55
|
+
if (!precision) {
|
|
56
|
+
return ValueType.INT;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
switch (precision) {
|
|
60
|
+
case Precision.INT:
|
|
61
|
+
return ValueType.INT;
|
|
62
|
+
case Precision.DOUBLE:
|
|
63
|
+
return ValueType.DOUBLE;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { MeterProvider, MetricReader, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
|
|
2
|
+
import { env } from '../../util/env.js';
|
|
3
|
+
import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
|
|
4
|
+
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
|
|
5
|
+
import { Resource } from '@opentelemetry/resources';
|
|
6
|
+
import { ServiceContext } from '../../system/ServiceContext.js';
|
|
7
|
+
import { OpenTelemetryMetricsFactory } from './OpenTelemetryMetricsFactory.js';
|
|
8
|
+
import { MetricsFactory } from '../metrics-interfaces.js';
|
|
9
|
+
|
|
10
|
+
export interface RuntimeMetadata {
|
|
11
|
+
[key: string]: string | number | undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function createOpenTelemetryMetricsFactory(context: ServiceContext): MetricsFactory {
|
|
15
|
+
const { configuration, lifeCycleEngine, storageEngine } = context;
|
|
16
|
+
const configuredExporters: MetricReader[] = [];
|
|
17
|
+
|
|
18
|
+
if (env.METRICS_PORT) {
|
|
19
|
+
const prometheusExporter = new PrometheusExporter({ port: env.METRICS_PORT, preventServerStart: true });
|
|
20
|
+
configuredExporters.push(prometheusExporter);
|
|
21
|
+
|
|
22
|
+
lifeCycleEngine.withLifecycle(prometheusExporter, {
|
|
23
|
+
start: () => prometheusExporter.startServer()
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!configuration.telemetry.disable_telemetry_sharing) {
|
|
28
|
+
const periodicExporter = new PeriodicExportingMetricReader({
|
|
29
|
+
exporter: new OTLPMetricExporter({
|
|
30
|
+
url: configuration.telemetry.internal_service_endpoint
|
|
31
|
+
}),
|
|
32
|
+
exportIntervalMillis: 1000 * 60 * 5 // 5 minutes
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
configuredExporters.push(periodicExporter);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let resolvedMetadata: (metadata: RuntimeMetadata) => void;
|
|
39
|
+
const runtimeMetadata: Promise<RuntimeMetadata> = new Promise((resolve) => {
|
|
40
|
+
resolvedMetadata = resolve;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
lifeCycleEngine.withLifecycle(null, {
|
|
44
|
+
start: async () => {
|
|
45
|
+
const bucketStorage = storageEngine.activeBucketStorage;
|
|
46
|
+
try {
|
|
47
|
+
const instanceId = await bucketStorage.getPowerSyncInstanceId();
|
|
48
|
+
resolvedMetadata({ ['instance_id']: instanceId });
|
|
49
|
+
} catch (err) {
|
|
50
|
+
resolvedMetadata({ ['instance_id']: 'Unknown' });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const meterProvider = new MeterProvider({
|
|
56
|
+
resource: new Resource(
|
|
57
|
+
{
|
|
58
|
+
['service']: 'PowerSync'
|
|
59
|
+
},
|
|
60
|
+
runtimeMetadata
|
|
61
|
+
),
|
|
62
|
+
readers: configuredExporters
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
lifeCycleEngine.withLifecycle(meterProvider, {
|
|
66
|
+
stop: async () => {
|
|
67
|
+
await meterProvider.shutdown();
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const meter = meterProvider.getMeter('powersync');
|
|
72
|
+
|
|
73
|
+
return new OpenTelemetryMetricsFactory(meter);
|
|
74
|
+
}
|
|
@@ -2,10 +2,12 @@ import { container, logger } from '@powersync/lib-services-framework';
|
|
|
2
2
|
import winston from 'winston';
|
|
3
3
|
import * as storage from '../storage/storage-index.js';
|
|
4
4
|
import { ErrorRateLimiter } from './ErrorRateLimiter.js';
|
|
5
|
+
import { MetricsEngine } from '../metrics/MetricsEngine.js';
|
|
5
6
|
|
|
6
7
|
export interface AbstractReplicationJobOptions {
|
|
7
8
|
id: string;
|
|
8
9
|
storage: storage.SyncRulesBucketStorage;
|
|
10
|
+
metrics: MetricsEngine;
|
|
9
11
|
lock: storage.ReplicationLock;
|
|
10
12
|
rateLimiter: ErrorRateLimiter;
|
|
11
13
|
}
|
|
@@ -7,6 +7,7 @@ import { SyncRulesProvider } from '../util/config/sync-rules/sync-rules-provider
|
|
|
7
7
|
import { AbstractReplicationJob } from './AbstractReplicationJob.js';
|
|
8
8
|
import { ErrorRateLimiter } from './ErrorRateLimiter.js';
|
|
9
9
|
import { ConnectionTestResult } from './ReplicationModule.js';
|
|
10
|
+
import { MetricsEngine } from '../metrics/MetricsEngine.js';
|
|
10
11
|
|
|
11
12
|
// 5 minutes
|
|
12
13
|
const PING_INTERVAL = 1_000_000_000n * 300n;
|
|
@@ -19,6 +20,7 @@ export interface CreateJobOptions {
|
|
|
19
20
|
export interface AbstractReplicatorOptions {
|
|
20
21
|
id: string;
|
|
21
22
|
storageEngine: StorageEngine;
|
|
23
|
+
metricsEngine: MetricsEngine;
|
|
22
24
|
syncRuleProvider: SyncRulesProvider;
|
|
23
25
|
/**
|
|
24
26
|
* This limits the effect of retries when there is a persistent issue.
|
|
@@ -33,6 +35,7 @@ export interface AbstractReplicatorOptions {
|
|
|
33
35
|
*/
|
|
34
36
|
export abstract class AbstractReplicator<T extends AbstractReplicationJob = AbstractReplicationJob> {
|
|
35
37
|
protected logger: winston.Logger;
|
|
38
|
+
|
|
36
39
|
/**
|
|
37
40
|
* Map of replication jobs by sync rule id. Usually there is only one running job, but there could be two when
|
|
38
41
|
* transitioning to a new set of sync rules.
|
|
@@ -72,6 +75,10 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
|
|
|
72
75
|
return this.options.rateLimiter;
|
|
73
76
|
}
|
|
74
77
|
|
|
78
|
+
protected get metrics() {
|
|
79
|
+
return this.options.metricsEngine;
|
|
80
|
+
}
|
|
81
|
+
|
|
75
82
|
public async start(): Promise<void> {
|
|
76
83
|
this.runLoop().catch((e) => {
|
|
77
84
|
this.logger.error('Data source fatal replication error', e);
|
|
@@ -64,6 +64,14 @@ export abstract class ReplicationModule<TConfig extends DataSourceConfig>
|
|
|
64
64
|
*/
|
|
65
65
|
protected abstract createReplicator(context: system.ServiceContext): AbstractReplicator;
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Any additional initialization specific to the module should be added here. Will be called if necessary after the
|
|
69
|
+
* main initialization has been completed
|
|
70
|
+
* @param context
|
|
71
|
+
* @protected
|
|
72
|
+
*/
|
|
73
|
+
protected abstract onInitialized(context: system.ServiceContext): Promise<void>;
|
|
74
|
+
|
|
67
75
|
public abstract testConnection(config: TConfig): Promise<ConnectionTestResult>;
|
|
68
76
|
|
|
69
77
|
/**
|
|
@@ -93,6 +101,8 @@ export abstract class ReplicationModule<TConfig extends DataSourceConfig>
|
|
|
93
101
|
|
|
94
102
|
context.replicationEngine?.register(this.createReplicator(context));
|
|
95
103
|
context.routerEngine?.registerAPI(this.createRouteAPIAdapter());
|
|
104
|
+
|
|
105
|
+
await this.onInitialized(context);
|
|
96
106
|
}
|
|
97
107
|
|
|
98
108
|
protected decodeConfig(config: TConfig): void {
|