@powersync/service-core 0.2.2 → 0.4.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 +31 -0
- package/dist/api/diagnostics.js +2 -2
- package/dist/api/diagnostics.js.map +1 -1
- package/dist/api/schema.js.map +1 -1
- package/dist/auth/CachedKeyCollector.js.map +1 -1
- package/dist/auth/JwtPayload.d.ts +6 -2
- package/dist/auth/KeySpec.js.map +1 -1
- package/dist/auth/KeyStore.js +3 -9
- package/dist/auth/KeyStore.js.map +1 -1
- package/dist/auth/LeakyBucket.js.map +1 -1
- package/dist/auth/RemoteJWKSCollector.js.map +1 -1
- package/dist/auth/SupabaseKeyCollector.js.map +1 -1
- package/dist/db/mongo.js.map +1 -1
- package/dist/entry/cli-entry.js +2 -2
- package/dist/entry/cli-entry.js.map +1 -1
- package/dist/entry/commands/config-command.js.map +1 -1
- package/dist/entry/commands/migrate-action.js +12 -4
- package/dist/entry/commands/migrate-action.js.map +1 -1
- package/dist/entry/commands/start-action.js.map +1 -1
- package/dist/entry/commands/teardown-action.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/locks/LockManager.d.ts +10 -0
- package/dist/locks/LockManager.js +7 -0
- package/dist/locks/LockManager.js.map +1 -0
- package/dist/locks/MongoLocks.d.ts +36 -0
- package/dist/locks/MongoLocks.js +81 -0
- package/dist/locks/MongoLocks.js.map +1 -0
- package/dist/locks/locks-index.d.ts +2 -0
- package/dist/locks/locks-index.js +3 -0
- package/dist/locks/locks-index.js.map +1 -0
- package/dist/metrics/Metrics.js +6 -6
- package/dist/metrics/Metrics.js.map +1 -1
- package/dist/migrations/db/migrations/1684951997326-init.js.map +1 -1
- package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -1
- package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +1 -1
- package/dist/migrations/definitions.d.ts +18 -0
- package/dist/migrations/definitions.js +6 -0
- package/dist/migrations/definitions.js.map +1 -0
- package/dist/migrations/executor.d.ts +16 -0
- package/dist/migrations/executor.js +64 -0
- package/dist/migrations/executor.js.map +1 -0
- package/dist/migrations/migrations-index.d.ts +3 -0
- package/dist/migrations/migrations-index.js +4 -0
- package/dist/migrations/migrations-index.js.map +1 -0
- package/dist/migrations/migrations.d.ts +1 -1
- package/dist/migrations/migrations.js +12 -8
- package/dist/migrations/migrations.js.map +1 -1
- package/dist/migrations/store/migration-store.d.ts +11 -0
- package/dist/migrations/store/migration-store.js +46 -0
- package/dist/migrations/store/migration-store.js.map +1 -0
- package/dist/replication/ErrorRateLimiter.js.map +1 -1
- package/dist/replication/PgRelation.js.map +1 -1
- package/dist/replication/WalConnection.js.map +1 -1
- package/dist/replication/WalStream.d.ts +0 -1
- package/dist/replication/WalStream.js +21 -25
- package/dist/replication/WalStream.js.map +1 -1
- package/dist/replication/WalStreamManager.js +12 -13
- package/dist/replication/WalStreamManager.js.map +1 -1
- package/dist/replication/WalStreamRunner.js +8 -8
- package/dist/replication/WalStreamRunner.js.map +1 -1
- package/dist/replication/util.js.map +1 -1
- package/dist/routes/auth.d.ts +8 -10
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/endpoints/admin.d.ts +1011 -0
- package/dist/routes/{admin.js → endpoints/admin.js} +33 -18
- package/dist/routes/endpoints/admin.js.map +1 -0
- package/dist/routes/endpoints/checkpointing.d.ts +76 -0
- package/dist/routes/endpoints/checkpointing.js +36 -0
- package/dist/routes/endpoints/checkpointing.js.map +1 -0
- package/dist/routes/endpoints/dev.d.ts +312 -0
- package/dist/routes/{dev.js → endpoints/dev.js} +25 -16
- package/dist/routes/endpoints/dev.js.map +1 -0
- package/dist/routes/endpoints/route-endpoints-index.d.ts +6 -0
- package/dist/routes/endpoints/route-endpoints-index.js +7 -0
- package/dist/routes/endpoints/route-endpoints-index.js.map +1 -0
- package/dist/routes/endpoints/socket-route.d.ts +2 -0
- package/dist/routes/{socket-route.js → endpoints/socket-route.js} +12 -12
- package/dist/routes/endpoints/socket-route.js.map +1 -0
- package/dist/routes/endpoints/sync-rules.d.ts +174 -0
- package/dist/routes/{sync-rules.js → endpoints/sync-rules.js} +44 -24
- package/dist/routes/endpoints/sync-rules.js.map +1 -0
- package/dist/routes/endpoints/sync-stream.d.ts +132 -0
- package/dist/routes/{sync-stream.js → endpoints/sync-stream.js} +28 -19
- package/dist/routes/endpoints/sync-stream.js.map +1 -0
- package/dist/routes/hooks.d.ts +10 -0
- package/dist/routes/hooks.js +31 -0
- package/dist/routes/hooks.js.map +1 -0
- package/dist/routes/route-register.d.ts +10 -0
- package/dist/routes/route-register.js +87 -0
- package/dist/routes/route-register.js.map +1 -0
- package/dist/routes/router.d.ts +16 -4
- package/dist/routes/router.js +6 -1
- package/dist/routes/router.js.map +1 -1
- package/dist/routes/routes-index.d.ts +5 -3
- package/dist/routes/routes-index.js +5 -3
- package/dist/routes/routes-index.js.map +1 -1
- package/dist/runner/teardown.js +9 -9
- package/dist/runner/teardown.js.map +1 -1
- package/dist/storage/BucketStorage.d.ts +3 -0
- package/dist/storage/BucketStorage.js.map +1 -1
- package/dist/storage/ChecksumCache.js.map +1 -1
- package/dist/storage/MongoBucketStorage.js +5 -5
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/SourceTable.js.map +1 -1
- package/dist/storage/mongo/MongoBucketBatch.js +23 -18
- package/dist/storage/mongo/MongoBucketBatch.js.map +1 -1
- package/dist/storage/mongo/MongoIdSequence.js.map +1 -1
- package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/mongo/MongoSyncRulesLock.js +3 -3
- package/dist/storage/mongo/MongoSyncRulesLock.js.map +1 -1
- package/dist/storage/mongo/OperationBatch.js.map +1 -1
- package/dist/storage/mongo/PersistedBatch.js +2 -2
- package/dist/storage/mongo/PersistedBatch.js.map +1 -1
- package/dist/storage/mongo/db.d.ts +2 -2
- package/dist/storage/mongo/db.js.map +1 -1
- package/dist/storage/mongo/util.js.map +1 -1
- package/dist/sync/BroadcastIterable.js.map +1 -1
- package/dist/sync/LastValueSink.js.map +1 -1
- package/dist/sync/merge.js.map +1 -1
- package/dist/sync/safeRace.js.map +1 -1
- package/dist/sync/sync.d.ts +2 -2
- package/dist/sync/sync.js +5 -5
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/util.js.map +1 -1
- package/dist/system/CorePowerSyncSystem.d.ts +12 -7
- package/dist/system/CorePowerSyncSystem.js +26 -2
- package/dist/system/CorePowerSyncSystem.js.map +1 -1
- package/dist/system/system-index.d.ts +1 -0
- package/dist/system/system-index.js +2 -0
- package/dist/system/system-index.js.map +1 -0
- package/dist/util/Mutex.js.map +1 -1
- package/dist/util/PgManager.js.map +1 -1
- package/dist/util/alerting.d.ts +0 -2
- package/dist/util/alerting.js +0 -6
- package/dist/util/alerting.js.map +1 -1
- package/dist/util/config/collectors/config-collector.js +3 -3
- package/dist/util/config/collectors/config-collector.js.map +1 -1
- package/dist/util/config/collectors/impl/base64-config-collector.js.map +1 -1
- package/dist/util/config/collectors/impl/filesystem-config-collector.js +7 -5
- package/dist/util/config/collectors/impl/filesystem-config-collector.js.map +1 -1
- package/dist/util/config/compound-config-collector.js +4 -4
- package/dist/util/config/compound-config-collector.js.map +1 -1
- package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js.map +1 -1
- package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js.map +1 -1
- package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.js.map +1 -1
- package/dist/util/config.js.map +1 -1
- package/dist/util/env.d.ts +1 -2
- package/dist/util/env.js +3 -2
- package/dist/util/env.js.map +1 -1
- package/dist/util/memory-tracking.js +2 -2
- package/dist/util/memory-tracking.js.map +1 -1
- package/dist/util/migration_lib.js.map +1 -1
- package/dist/util/pgwire_utils.js +2 -2
- package/dist/util/pgwire_utils.js.map +1 -1
- package/dist/util/populate_test_data.js.map +1 -1
- package/dist/util/secs.js.map +1 -1
- package/dist/util/utils.js +4 -4
- package/dist/util/utils.js.map +1 -1
- package/package.json +13 -10
- package/src/api/diagnostics.ts +5 -5
- package/src/api/schema.ts +1 -1
- package/src/auth/JwtPayload.ts +6 -2
- package/src/auth/KeyStore.ts +3 -9
- package/src/entry/cli-entry.ts +3 -4
- package/src/entry/commands/config-command.ts +1 -1
- package/src/entry/commands/migrate-action.ts +14 -6
- package/src/entry/commands/start-action.ts +1 -1
- package/src/entry/commands/teardown-action.ts +1 -1
- package/src/index.ts +5 -2
- package/src/locks/LockManager.ts +16 -0
- package/src/locks/MongoLocks.ts +142 -0
- package/src/locks/locks-index.ts +2 -0
- package/src/metrics/Metrics.ts +8 -8
- package/src/migrations/db/migrations/1684951997326-init.ts +3 -3
- package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +3 -3
- package/src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts +2 -2
- package/src/migrations/definitions.ts +21 -0
- package/src/migrations/executor.ts +87 -0
- package/src/migrations/migrations-index.ts +3 -0
- package/src/migrations/migrations.ts +15 -11
- package/src/migrations/store/migration-store.ts +63 -0
- package/src/replication/WalConnection.ts +2 -2
- package/src/replication/WalStream.ts +24 -29
- package/src/replication/WalStreamManager.ts +14 -15
- package/src/replication/WalStreamRunner.ts +10 -10
- package/src/replication/util.ts +1 -1
- package/src/routes/auth.ts +22 -16
- package/src/routes/endpoints/admin.ts +237 -0
- package/src/routes/endpoints/checkpointing.ts +41 -0
- package/src/routes/endpoints/dev.ts +199 -0
- package/src/routes/endpoints/route-endpoints-index.ts +6 -0
- package/src/routes/{socket-route.ts → endpoints/socket-route.ts} +13 -16
- package/src/routes/endpoints/sync-rules.ts +227 -0
- package/src/routes/endpoints/sync-stream.ts +98 -0
- package/src/routes/hooks.ts +45 -0
- package/src/routes/route-register.ts +104 -0
- package/src/routes/router.ts +34 -6
- package/src/routes/routes-index.ts +5 -4
- package/src/runner/teardown.ts +9 -9
- package/src/storage/BucketStorage.ts +7 -2
- package/src/storage/ChecksumCache.ts +2 -2
- package/src/storage/MongoBucketStorage.ts +8 -8
- package/src/storage/SourceTable.ts +2 -2
- package/src/storage/mongo/MongoBucketBatch.ts +29 -22
- package/src/storage/mongo/MongoSyncBucketStorage.ts +3 -3
- package/src/storage/mongo/MongoSyncRulesLock.ts +3 -3
- package/src/storage/mongo/OperationBatch.ts +1 -1
- package/src/storage/mongo/PersistedBatch.ts +3 -3
- package/src/storage/mongo/db.ts +3 -4
- package/src/sync/sync.ts +11 -11
- package/src/sync/util.ts +2 -2
- package/src/system/CorePowerSyncSystem.ts +31 -10
- package/src/system/system-index.ts +1 -0
- package/src/util/alerting.ts +0 -8
- package/src/util/config/collectors/config-collector.ts +5 -3
- package/src/util/config/collectors/impl/filesystem-config-collector.ts +8 -6
- package/src/util/config/compound-config-collector.ts +4 -4
- package/src/util/env.ts +4 -2
- package/src/util/memory-tracking.ts +2 -2
- package/src/util/pgwire_utils.ts +3 -3
- package/src/util/utils.ts +5 -5
- package/test/src/auth.test.ts +4 -2
- package/test/src/data_storage.test.ts +181 -19
- package/test/src/env.ts +6 -6
- package/test/src/setup.ts +7 -0
- package/test/src/slow_tests.test.ts +45 -6
- package/test/src/sync.test.ts +6 -5
- package/test/tsconfig.json +1 -1
- package/tsconfig.json +5 -6
- package/tsconfig.tsbuildinfo +1 -1
- package/vitest.config.ts +1 -3
- package/dist/migrations/db/store.d.ts +0 -3
- package/dist/migrations/db/store.js +0 -10
- package/dist/migrations/db/store.js.map +0 -1
- package/dist/routes/admin.d.ts +0 -7
- package/dist/routes/admin.js.map +0 -1
- package/dist/routes/checkpointing.d.ts +0 -3
- package/dist/routes/checkpointing.js +0 -30
- package/dist/routes/checkpointing.js.map +0 -1
- package/dist/routes/dev.d.ts +0 -6
- package/dist/routes/dev.js.map +0 -1
- package/dist/routes/route-generators.d.ts +0 -15
- package/dist/routes/route-generators.js +0 -32
- package/dist/routes/route-generators.js.map +0 -1
- package/dist/routes/socket-route.d.ts +0 -2
- package/dist/routes/socket-route.js.map +0 -1
- package/dist/routes/sync-rules.d.ts +0 -6
- package/dist/routes/sync-rules.js.map +0 -1
- package/dist/routes/sync-stream.d.ts +0 -5
- package/dist/routes/sync-stream.js.map +0 -1
- package/src/migrations/db/store.ts +0 -11
- package/src/routes/admin.ts +0 -229
- package/src/routes/checkpointing.ts +0 -38
- package/src/routes/dev.ts +0 -194
- package/src/routes/route-generators.ts +0 -39
- package/src/routes/sync-rules.ts +0 -210
- package/src/routes/sync-stream.ts +0 -95
- package/test/src/sql_functions.test.ts +0 -254
- package/test/src/sql_operators.test.ts +0 -132
- package/test/src/sync_rules.test.ts +0 -1053
package/src/entry/cli-entry.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
|
|
3
|
-
import * as
|
|
4
|
-
|
|
5
|
-
import * as utils from '@/util/util-index.js';
|
|
3
|
+
import * as utils from '../util/util-index.js';
|
|
6
4
|
import { registerMigrationAction } from './commands/migrate-action.js';
|
|
7
5
|
import { registerTearDownAction } from './commands/teardown-action.js';
|
|
8
6
|
import { registerStartAction } from './entry-index.js';
|
|
7
|
+
import { logger } from '@powersync/lib-services-framework';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* Generates a Commander program which serves as the entry point
|
|
@@ -33,7 +32,7 @@ export function generateEntryProgram(startHandlers?: Record<utils.ServiceRunner,
|
|
|
33
32
|
try {
|
|
34
33
|
await entryProgram.parseAsync();
|
|
35
34
|
} catch (e) {
|
|
36
|
-
|
|
35
|
+
logger.error('Fatal error', e);
|
|
37
36
|
process.exit(1);
|
|
38
37
|
}
|
|
39
38
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import { Direction } from '@journeyapps-platform/micro-migrate';
|
|
3
2
|
|
|
4
3
|
import { extractRunnerOptions, wrapConfigCommand } from './config-command.js';
|
|
5
|
-
import { migrate } from '
|
|
4
|
+
import { migrate } from '../../migrations/migrations.js';
|
|
5
|
+
import { Direction } from '../../migrations/definitions.js';
|
|
6
|
+
import { logger } from '@powersync/lib-services-framework';
|
|
6
7
|
|
|
7
8
|
const COMMAND_NAME = 'migrate';
|
|
8
9
|
|
|
@@ -17,9 +18,16 @@ export function registerMigrationAction(program: Command) {
|
|
|
17
18
|
.action(async (direction: Direction, options) => {
|
|
18
19
|
const runnerConfig = extractRunnerOptions(options);
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
try {
|
|
22
|
+
await migrate({
|
|
23
|
+
direction,
|
|
24
|
+
runner_config: runnerConfig
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
process.exit(0);
|
|
28
|
+
} catch (e) {
|
|
29
|
+
logger.error(`Migration failure`, e);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
24
32
|
});
|
|
25
33
|
}
|
package/src/index.ts
CHANGED
|
@@ -12,11 +12,14 @@ export * as db from './db/db-index.js';
|
|
|
12
12
|
export * from './entry/entry-index.js';
|
|
13
13
|
export * as entry from './entry/entry-index.js';
|
|
14
14
|
|
|
15
|
+
// Re-export framework for easy use of Container API
|
|
16
|
+
export * as framework from '@powersync/lib-services-framework';
|
|
17
|
+
|
|
15
18
|
export * from './metrics/Metrics.js';
|
|
16
19
|
export * as metrics from './metrics/Metrics.js';
|
|
17
20
|
|
|
18
21
|
export * from './migrations/migrations.js';
|
|
19
|
-
export * as migrations from './migrations/migrations.js';
|
|
22
|
+
export * as migrations from './migrations/migrations-index.js';
|
|
20
23
|
|
|
21
24
|
export * from './replication/replication-index.js';
|
|
22
25
|
export * as replication from './replication/replication-index.js';
|
|
@@ -31,7 +34,7 @@ export * from './sync/sync-index.js';
|
|
|
31
34
|
export * as sync from './sync/sync-index.js';
|
|
32
35
|
|
|
33
36
|
export * from './system/CorePowerSyncSystem.js';
|
|
34
|
-
export * as system from './system/
|
|
37
|
+
export * as system from './system/system-index.js';
|
|
35
38
|
|
|
36
39
|
export * from './util/util-index.js';
|
|
37
40
|
export * as utils from './util/util-index.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as bson from 'bson';
|
|
2
|
+
|
|
3
|
+
export class LockActiveError extends Error {
|
|
4
|
+
constructor() {
|
|
5
|
+
super('Lock is already active');
|
|
6
|
+
this.name = this.constructor.name;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type LockManager = {
|
|
11
|
+
acquire: () => Promise<bson.ObjectId | null>;
|
|
12
|
+
refresh: (lock_id: bson.ObjectId) => Promise<void>;
|
|
13
|
+
release: (lock_id: bson.ObjectId) => Promise<void>;
|
|
14
|
+
|
|
15
|
+
lock: (handler: (refresh: () => Promise<void>) => Promise<void>) => Promise<void>;
|
|
16
|
+
};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import * as mongo from 'mongodb';
|
|
2
|
+
import * as bson from 'bson';
|
|
3
|
+
import { LockActiveError, LockManager } from './LockManager.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Lock Document Schema
|
|
7
|
+
*/
|
|
8
|
+
export type Lock = {
|
|
9
|
+
name: string;
|
|
10
|
+
active_lock?: {
|
|
11
|
+
lock_id: bson.ObjectId;
|
|
12
|
+
ts: Date;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type Collection = mongo.Collection<Lock>;
|
|
17
|
+
|
|
18
|
+
export type AcquireLockParams = {
|
|
19
|
+
/**
|
|
20
|
+
* Name of the process/user trying to acquire the lock.
|
|
21
|
+
*/
|
|
22
|
+
name: string;
|
|
23
|
+
/**
|
|
24
|
+
* The TTL of the lock (ms). Default: 60000 ms (1 min)
|
|
25
|
+
*/
|
|
26
|
+
timeout?: number;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const DEFAULT_LOCK_TIMEOUT = 60 * 1000; // 1 minute
|
|
30
|
+
|
|
31
|
+
const acquireLock = async (collection: Collection, params: AcquireLockParams) => {
|
|
32
|
+
const now = new Date();
|
|
33
|
+
const lock_timeout = params.timeout ?? DEFAULT_LOCK_TIMEOUT;
|
|
34
|
+
const lock_id = new bson.ObjectId();
|
|
35
|
+
|
|
36
|
+
await collection.updateOne(
|
|
37
|
+
{
|
|
38
|
+
name: params.name
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
$setOnInsert: {
|
|
42
|
+
name: params.name
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
upsert: true
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const expired_ts = now.getTime() - lock_timeout;
|
|
51
|
+
|
|
52
|
+
const res = await collection.updateOne(
|
|
53
|
+
{
|
|
54
|
+
$and: [
|
|
55
|
+
{ name: params.name },
|
|
56
|
+
{
|
|
57
|
+
$or: [{ active_lock: { $exists: false } }, { 'active_lock.ts': { $lte: new Date(expired_ts) } }]
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
$set: {
|
|
63
|
+
active_lock: {
|
|
64
|
+
lock_id: lock_id,
|
|
65
|
+
ts: now
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
if (res.modifiedCount === 0) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return lock_id;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const refreshLock = async (collection: Collection, lock_id: bson.ObjectId) => {
|
|
79
|
+
const res = await collection.updateOne(
|
|
80
|
+
{
|
|
81
|
+
'active_lock.lock_id': lock_id
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
$set: {
|
|
85
|
+
'active_lock.ts': new Date()
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
if (res.modifiedCount === 0) {
|
|
91
|
+
throw new Error('Lock not found, could not refresh');
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const releaseLock = async (collection: Collection, lock_id: bson.ObjectId) => {
|
|
96
|
+
const res = await collection.updateOne(
|
|
97
|
+
{
|
|
98
|
+
'active_lock.lock_id': lock_id
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
$unset: {
|
|
102
|
+
active_lock: true
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
if (res.modifiedCount === 0) {
|
|
108
|
+
throw new Error('Lock not found, could not release');
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export type CreateLockManagerParams = {
|
|
113
|
+
/**
|
|
114
|
+
* Name of the process/user trying to acquire the lock.
|
|
115
|
+
*/
|
|
116
|
+
name: string;
|
|
117
|
+
/**
|
|
118
|
+
* The TTL for each lock (ms). Default: 60000 ms (1 min)
|
|
119
|
+
*/
|
|
120
|
+
timeout?: number;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export const createMongoLockManager = (collection: Collection, params: CreateLockManagerParams): LockManager => {
|
|
124
|
+
return {
|
|
125
|
+
acquire: () => acquireLock(collection, params),
|
|
126
|
+
refresh: (lock_id: bson.ObjectId) => refreshLock(collection, lock_id),
|
|
127
|
+
release: (lock_id: bson.ObjectId) => releaseLock(collection, lock_id),
|
|
128
|
+
|
|
129
|
+
lock: async (handler) => {
|
|
130
|
+
const lock_id = await acquireLock(collection, params);
|
|
131
|
+
if (!lock_id) {
|
|
132
|
+
throw new LockActiveError();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
await handler(() => refreshLock(collection, lock_id));
|
|
137
|
+
} finally {
|
|
138
|
+
await releaseLock(collection, lock_id);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
};
|
package/src/metrics/Metrics.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import * as micro from '@journeyapps-platform/micro';
|
|
2
1
|
import { Attributes, Counter, ObservableGauge, UpDownCounter, ValueType } from '@opentelemetry/api';
|
|
3
2
|
import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
|
|
4
3
|
import { MeterProvider, MetricReader, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
|
|
5
4
|
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
|
|
6
5
|
import * as jpgwire from '@powersync/service-jpgwire';
|
|
7
|
-
import * as util from '
|
|
8
|
-
import * as storage from '
|
|
6
|
+
import * as util from '../util/util-index.js';
|
|
7
|
+
import * as storage from '../storage/storage-index.js';
|
|
9
8
|
import { CorePowerSyncSystem } from '../system/CorePowerSyncSystem.js';
|
|
10
9
|
import { Resource } from '@opentelemetry/resources';
|
|
10
|
+
import { logger } from '@powersync/lib-services-framework';
|
|
11
11
|
|
|
12
12
|
export interface MetricsOptions {
|
|
13
13
|
disable_telemetry_sharing: boolean;
|
|
@@ -144,9 +144,9 @@ export class Metrics {
|
|
|
144
144
|
if (Metrics.instance) {
|
|
145
145
|
return;
|
|
146
146
|
}
|
|
147
|
-
|
|
147
|
+
logger.info('Configuring telemetry.');
|
|
148
148
|
|
|
149
|
-
|
|
149
|
+
logger.info(
|
|
150
150
|
`
|
|
151
151
|
Attention:
|
|
152
152
|
PowerSync collects completely anonymous telemetry regarding usage.
|
|
@@ -164,7 +164,7 @@ Anonymous telemetry is currently: ${options.disable_telemetry_sharing ? 'disable
|
|
|
164
164
|
configuredExporters.push(prometheusExporter);
|
|
165
165
|
|
|
166
166
|
if (!options.disable_telemetry_sharing) {
|
|
167
|
-
|
|
167
|
+
logger.info('Sharing anonymous telemetry');
|
|
168
168
|
const periodicExporter = new PeriodicExportingMetricReader({
|
|
169
169
|
exporter: new OTLPMetricExporter({
|
|
170
170
|
url: options.internal_metrics_endpoint
|
|
@@ -189,7 +189,7 @@ Anonymous telemetry is currently: ${options.disable_telemetry_sharing ? 'disable
|
|
|
189
189
|
|
|
190
190
|
Metrics.instance = new Metrics(meterProvider, prometheusExporter);
|
|
191
191
|
|
|
192
|
-
|
|
192
|
+
logger.info('Telemetry configuration complete.');
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
public async shutdown(): Promise<void> {
|
|
@@ -212,7 +212,7 @@ Anonymous telemetry is currently: ${options.disable_telemetry_sharing ? 'disable
|
|
|
212
212
|
function getMetrics() {
|
|
213
213
|
if (cachedRequest == null || Date.now() - cacheTimestamp > MINIMUM_INTERVAL) {
|
|
214
214
|
cachedRequest = system.storage.getStorageMetrics().catch((e) => {
|
|
215
|
-
|
|
215
|
+
logger.error(`Failed to get storage metrics`, e);
|
|
216
216
|
return null;
|
|
217
217
|
});
|
|
218
218
|
cacheTimestamp = Date.now();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as mongo from '
|
|
2
|
-
import * as storage from '
|
|
3
|
-
import * as utils from '
|
|
1
|
+
import * as mongo from '../../../db/mongo.js';
|
|
2
|
+
import * as storage from '../../../storage/storage-index.js';
|
|
3
|
+
import * as utils from '../../../util/util-index.js';
|
|
4
4
|
|
|
5
5
|
export const up = async (context?: utils.MigrationContext) => {
|
|
6
6
|
const config = await utils.loadConfig(context?.runner_config);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as mongo from '
|
|
2
|
-
import * as storage from '
|
|
3
|
-
import * as utils from '
|
|
1
|
+
import * as mongo from '../../../db/mongo.js';
|
|
2
|
+
import * as storage from '../../../storage/storage-index.js';
|
|
3
|
+
import * as utils from '../../../util/util-index.js';
|
|
4
4
|
|
|
5
5
|
interface LegacySyncRulesDocument extends storage.SyncRuleDocument {
|
|
6
6
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as storage from '
|
|
2
|
-
import * as utils from '
|
|
1
|
+
import * as storage from '../../../storage/storage-index.js';
|
|
2
|
+
import * as utils from '../../../util/util-index.js';
|
|
3
3
|
|
|
4
4
|
export const up = async (context?: utils.MigrationContext) => {
|
|
5
5
|
const config = await utils.loadConfig(context?.runner_config);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type Migration = {
|
|
2
|
+
name: string;
|
|
3
|
+
up: () => Promise<void>;
|
|
4
|
+
down: () => Promise<void>;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export enum Direction {
|
|
8
|
+
Up = 'up',
|
|
9
|
+
Down = 'down'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type ExecutedMigration = {
|
|
13
|
+
name: string;
|
|
14
|
+
direction: Direction;
|
|
15
|
+
timestamp: Date;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type MigrationState = {
|
|
19
|
+
last_run: string;
|
|
20
|
+
log: ExecutedMigration[];
|
|
21
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { logger } from '@powersync/lib-services-framework';
|
|
2
|
+
import * as defs from './definitions.js';
|
|
3
|
+
import { MigrationStore } from './store/migration-store.js';
|
|
4
|
+
|
|
5
|
+
type ExecuteParams = {
|
|
6
|
+
migrations: defs.Migration[];
|
|
7
|
+
state?: defs.MigrationState;
|
|
8
|
+
|
|
9
|
+
direction: defs.Direction;
|
|
10
|
+
count?: number;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export async function* execute(params: ExecuteParams): AsyncGenerator<defs.ExecutedMigration> {
|
|
14
|
+
let migrations = [...params.migrations];
|
|
15
|
+
if (params.direction === defs.Direction.Down) {
|
|
16
|
+
migrations = migrations.reverse();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let index = 0;
|
|
20
|
+
|
|
21
|
+
if (params.state) {
|
|
22
|
+
// Find the index of the last run
|
|
23
|
+
index = migrations.findIndex((migration) => {
|
|
24
|
+
return migration.name === params.state!.last_run;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (index === -1) {
|
|
28
|
+
throw new Error(`The last run migration ${params.state?.last_run} was not found in the given set of migrations`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// If we are migrating down then we want to include the last run migration, otherwise we want to start at the next one
|
|
32
|
+
if (params.direction === defs.Direction.Up) {
|
|
33
|
+
index += 1;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
migrations = migrations.slice(index);
|
|
38
|
+
|
|
39
|
+
let i = 0;
|
|
40
|
+
for (const migration of migrations) {
|
|
41
|
+
if (params.count && params.count === i) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
logger.info(`Executing ${migration.name} (${params.direction})`);
|
|
46
|
+
try {
|
|
47
|
+
switch (params.direction) {
|
|
48
|
+
case defs.Direction.Up: {
|
|
49
|
+
await migration.up();
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
case defs.Direction.Down: {
|
|
53
|
+
await migration.down();
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
logger.debug(`Success`);
|
|
58
|
+
} catch (err) {
|
|
59
|
+
logger.error(`Failed`, err);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
yield {
|
|
64
|
+
name: migration.name,
|
|
65
|
+
direction: params.direction,
|
|
66
|
+
timestamp: new Date()
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
i++;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
type WriteLogsParams = {
|
|
74
|
+
store: MigrationStore;
|
|
75
|
+
state?: defs.MigrationState;
|
|
76
|
+
log_stream: Iterable<defs.ExecutedMigration> | AsyncIterable<defs.ExecutedMigration>;
|
|
77
|
+
};
|
|
78
|
+
export const writeLogsToStore = async (params: WriteLogsParams): Promise<void> => {
|
|
79
|
+
const log = [...(params.state?.log || [])];
|
|
80
|
+
for await (const migration of params.log_stream) {
|
|
81
|
+
log.push(migration);
|
|
82
|
+
await params.store.save({
|
|
83
|
+
last_run: migration.name,
|
|
84
|
+
log: log
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
};
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { locks } from '@journeyapps-platform/micro';
|
|
2
1
|
import * as fs from 'fs/promises';
|
|
3
2
|
import * as path from 'path';
|
|
4
3
|
import { fileURLToPath } from 'url';
|
|
5
4
|
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
import * as
|
|
9
|
-
import
|
|
5
|
+
import * as db from '../db/db-index.js';
|
|
6
|
+
import * as util from '../util/util-index.js';
|
|
7
|
+
import * as locks from '../locks/locks-index.js';
|
|
8
|
+
import { Direction } from './definitions.js';
|
|
9
|
+
import { createMongoMigrationStore } from './store/migration-store.js';
|
|
10
|
+
import { execute, writeLogsToStore } from './executor.js';
|
|
11
|
+
import { logger } from '@powersync/lib-services-framework';
|
|
10
12
|
|
|
11
13
|
const DEFAULT_MONGO_LOCK_COLLECTION = 'locks';
|
|
12
14
|
const MONGO_LOCK_PROCESS = 'migrations';
|
|
@@ -62,6 +64,7 @@ export const migrate = async (options: MigrationOptions) => {
|
|
|
62
64
|
const { storage } = config;
|
|
63
65
|
|
|
64
66
|
const client = db.mongo.createMongoClient(storage);
|
|
67
|
+
logger.info('Connecting to MongoDB');
|
|
65
68
|
await client.connect();
|
|
66
69
|
|
|
67
70
|
const clientDB = client.db(storage.database);
|
|
@@ -72,6 +75,7 @@ export const migrate = async (options: MigrationOptions) => {
|
|
|
72
75
|
});
|
|
73
76
|
|
|
74
77
|
// Only one process should execute this at a time.
|
|
78
|
+
logger.info('Acquiring lock');
|
|
75
79
|
const lockId = await manager.acquire();
|
|
76
80
|
|
|
77
81
|
if (!lockId) {
|
|
@@ -91,18 +95,15 @@ export const migrate = async (options: MigrationOptions) => {
|
|
|
91
95
|
process.addListener('beforeExit', releaseLock);
|
|
92
96
|
|
|
93
97
|
try {
|
|
98
|
+
logger.info('Loading migrations');
|
|
94
99
|
const migrations = await loadMigrations(MIGRATIONS_DIR, runner_config);
|
|
95
100
|
|
|
96
101
|
// Use the provided config to connect to Mongo
|
|
97
|
-
const store = createMongoMigrationStore(
|
|
98
|
-
uri: storage.uri,
|
|
99
|
-
database: storage.database,
|
|
100
|
-
username: storage.username,
|
|
101
|
-
password: storage.password
|
|
102
|
-
});
|
|
102
|
+
const store = createMongoMigrationStore(clientDB);
|
|
103
103
|
|
|
104
104
|
const state = await store.load();
|
|
105
105
|
|
|
106
|
+
logger.info('Running migrations');
|
|
106
107
|
const logStream = execute({
|
|
107
108
|
direction: direction,
|
|
108
109
|
migrations,
|
|
@@ -115,8 +116,11 @@ export const migrate = async (options: MigrationOptions) => {
|
|
|
115
116
|
state
|
|
116
117
|
});
|
|
117
118
|
} finally {
|
|
119
|
+
logger.info('Releasing lock');
|
|
118
120
|
await releaseLock();
|
|
121
|
+
logger.info('Closing database');
|
|
119
122
|
await client.close(true);
|
|
120
123
|
process.removeListener('beforeExit', releaseLock);
|
|
124
|
+
logger.info('Done with migrations');
|
|
121
125
|
}
|
|
122
126
|
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Db } from 'mongodb';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as defs from '../definitions.js';
|
|
4
|
+
|
|
5
|
+
export type MigrationStore = {
|
|
6
|
+
load: () => Promise<defs.MigrationState | undefined>;
|
|
7
|
+
save: (state: defs.MigrationState) => Promise<void>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A custom store for node-migrate which is used to save and load migrations that have
|
|
12
|
+
* been operated on to mongo.
|
|
13
|
+
*/
|
|
14
|
+
export const createMongoMigrationStore = (db: Db): MigrationStore => {
|
|
15
|
+
const collection = db.collection<defs.MigrationState>('migrations');
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
load: async () => {
|
|
19
|
+
const state_entry = await collection.findOne();
|
|
20
|
+
if (!state_entry) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const { _id, ...state } = state_entry;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* This is for backwards compatibility. A previous version of the migration tool used to save
|
|
28
|
+
* state as `lastRun`.
|
|
29
|
+
*/
|
|
30
|
+
let last_run = state.last_run;
|
|
31
|
+
if ('lastRun' in state) {
|
|
32
|
+
last_run = (state as any).lastRun;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* This is for backwards compatibility. A previous version of the migration tool used to include the
|
|
37
|
+
* file extension in migration names. This strips that extension off if it exists
|
|
38
|
+
*/
|
|
39
|
+
const extension = path.extname(last_run);
|
|
40
|
+
if (extension) {
|
|
41
|
+
last_run = last_run.replace(extension, '');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
last_run,
|
|
46
|
+
log: state.log || []
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
save: async (state: defs.MigrationState) => {
|
|
51
|
+
await collection.replaceOne(
|
|
52
|
+
{},
|
|
53
|
+
{
|
|
54
|
+
last_run: state.last_run,
|
|
55
|
+
log: state.log
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
upsert: true
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
};
|
|
@@ -3,8 +3,8 @@ import { pgwireRows } from '@powersync/service-jpgwire';
|
|
|
3
3
|
import { DEFAULT_TAG, SqlSyncRules, TablePattern } from '@powersync/service-sync-rules';
|
|
4
4
|
import { ReplicationError, TableInfo } from '@powersync/service-types';
|
|
5
5
|
|
|
6
|
-
import * as storage from '
|
|
7
|
-
import * as util from '
|
|
6
|
+
import * as storage from '../storage/storage-index.js';
|
|
7
|
+
import * as util from '../util/util-index.js';
|
|
8
8
|
|
|
9
9
|
import { ReplicaIdentityResult, getReplicationIdentityColumns } from './util.js';
|
|
10
10
|
/**
|