@powersync/service-core 0.0.0-dev-20240709124106 → 0.0.0-dev-20240725112650

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 (85) hide show
  1. package/CHANGELOG.md +39 -2
  2. package/dist/entry/cli-entry.js +2 -1
  3. package/dist/entry/cli-entry.js.map +1 -1
  4. package/dist/entry/commands/compact-action.d.ts +2 -0
  5. package/dist/entry/commands/compact-action.js +48 -0
  6. package/dist/entry/commands/compact-action.js.map +1 -0
  7. package/dist/entry/entry-index.d.ts +1 -0
  8. package/dist/entry/entry-index.js +1 -0
  9. package/dist/entry/entry-index.js.map +1 -1
  10. package/dist/routes/configure-fastify.d.ts +883 -0
  11. package/dist/routes/configure-fastify.js +58 -0
  12. package/dist/routes/configure-fastify.js.map +1 -0
  13. package/dist/routes/configure-rsocket.d.ts +13 -0
  14. package/dist/routes/configure-rsocket.js +46 -0
  15. package/dist/routes/configure-rsocket.js.map +1 -0
  16. package/dist/routes/endpoints/socket-route.js +10 -9
  17. package/dist/routes/endpoints/socket-route.js.map +1 -1
  18. package/dist/routes/endpoints/sync-stream.js +9 -1
  19. package/dist/routes/endpoints/sync-stream.js.map +1 -1
  20. package/dist/routes/route-register.d.ts +1 -1
  21. package/dist/routes/route-register.js +2 -1
  22. package/dist/routes/route-register.js.map +1 -1
  23. package/dist/routes/router-socket.d.ts +4 -4
  24. package/dist/routes/router-socket.js.map +1 -1
  25. package/dist/routes/router.d.ts +1 -0
  26. package/dist/routes/router.js.map +1 -1
  27. package/dist/routes/routes-index.d.ts +2 -0
  28. package/dist/routes/routes-index.js +2 -0
  29. package/dist/routes/routes-index.js.map +1 -1
  30. package/dist/storage/BucketStorage.d.ts +31 -1
  31. package/dist/storage/BucketStorage.js.map +1 -1
  32. package/dist/storage/mongo/MongoCompactor.d.ts +40 -0
  33. package/dist/storage/mongo/MongoCompactor.js +292 -0
  34. package/dist/storage/mongo/MongoCompactor.js.map +1 -0
  35. package/dist/storage/mongo/MongoSyncBucketStorage.d.ts +3 -2
  36. package/dist/storage/mongo/MongoSyncBucketStorage.js +19 -13
  37. package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -1
  38. package/dist/storage/mongo/models.d.ts +5 -4
  39. package/dist/storage/mongo/models.js.map +1 -1
  40. package/dist/storage/mongo/util.d.ts +3 -0
  41. package/dist/storage/mongo/util.js +22 -0
  42. package/dist/storage/mongo/util.js.map +1 -1
  43. package/dist/sync/RequestTracker.d.ts +9 -0
  44. package/dist/sync/RequestTracker.js +19 -0
  45. package/dist/sync/RequestTracker.js.map +1 -0
  46. package/dist/sync/sync-index.d.ts +1 -0
  47. package/dist/sync/sync-index.js +1 -0
  48. package/dist/sync/sync-index.js.map +1 -1
  49. package/dist/sync/sync.d.ts +2 -0
  50. package/dist/sync/sync.js +51 -18
  51. package/dist/sync/sync.js.map +1 -1
  52. package/dist/sync/util.d.ts +2 -1
  53. package/dist/sync/util.js +2 -3
  54. package/dist/sync/util.js.map +1 -1
  55. package/package.json +6 -6
  56. package/src/entry/cli-entry.ts +2 -1
  57. package/src/entry/commands/compact-action.ts +54 -0
  58. package/src/entry/entry-index.ts +1 -0
  59. package/src/routes/configure-fastify.ts +102 -0
  60. package/src/routes/configure-rsocket.ts +59 -0
  61. package/src/routes/endpoints/socket-route.ts +10 -9
  62. package/src/routes/endpoints/sync-stream.ts +10 -1
  63. package/src/routes/route-register.ts +3 -2
  64. package/src/routes/router-socket.ts +5 -5
  65. package/src/routes/router.ts +2 -0
  66. package/src/routes/routes-index.ts +2 -0
  67. package/src/storage/BucketStorage.ts +36 -1
  68. package/src/storage/mongo/MongoCompactor.ts +371 -0
  69. package/src/storage/mongo/MongoSyncBucketStorage.ts +25 -14
  70. package/src/storage/mongo/models.ts +5 -4
  71. package/src/storage/mongo/util.ts +25 -0
  72. package/src/sync/RequestTracker.ts +21 -0
  73. package/src/sync/sync-index.ts +1 -0
  74. package/src/sync/sync.ts +61 -17
  75. package/src/sync/util.ts +6 -2
  76. package/test/src/__snapshots__/sync.test.ts.snap +85 -0
  77. package/test/src/bucket_validation.test.ts +142 -0
  78. package/test/src/bucket_validation.ts +116 -0
  79. package/test/src/compacting.test.ts +207 -0
  80. package/test/src/data_storage.test.ts +19 -60
  81. package/test/src/slow_tests.test.ts +144 -102
  82. package/test/src/sync.test.ts +176 -28
  83. package/test/src/util.ts +65 -1
  84. package/test/src/wal_stream_utils.ts +13 -4
  85. package/tsconfig.tsbuildinfo +1 -1
package/dist/sync/sync.js CHANGED
@@ -3,7 +3,6 @@ import { Semaphore } from 'async-mutex';
3
3
  import { AbortError } from 'ix/aborterror.js';
4
4
  import * as util from '../util/util-index.js';
5
5
  import { logger } from '@powersync/lib-services-framework';
6
- import { Metrics } from '../metrics/Metrics.js';
7
6
  import { mergeAsyncIterables } from './merge.js';
8
7
  import { tokenStream } from './util.js';
9
8
  /**
@@ -12,7 +11,7 @@ import { tokenStream } from './util.js';
12
11
  const MAX_ACTIVE_CONNECTIONS = 10;
13
12
  const syncSemaphore = new Semaphore(MAX_ACTIVE_CONNECTIONS);
14
13
  export async function* streamResponse(options) {
15
- const { storage, params, syncParams, token, tokenStreamOptions, signal } = options;
14
+ const { storage, params, syncParams, token, tokenStreamOptions, tracker, signal } = options;
16
15
  // We also need to be able to abort, so we create our own controller.
17
16
  const controller = new AbortController();
18
17
  if (signal) {
@@ -24,7 +23,7 @@ export async function* streamResponse(options) {
24
23
  }
25
24
  }
26
25
  const ki = tokenStream(token, controller.signal, tokenStreamOptions);
27
- const stream = streamResponseInner(storage, params, syncParams, controller.signal);
26
+ const stream = streamResponseInner(storage, params, syncParams, tracker, controller.signal);
28
27
  // Merge the two streams, and abort as soon as one of the streams end.
29
28
  const merged = mergeAsyncIterables([stream, ki], controller.signal);
30
29
  try {
@@ -44,7 +43,7 @@ export async function* streamResponse(options) {
44
43
  controller.abort();
45
44
  }
46
45
  }
47
- async function* streamResponseInner(storage, params, syncParams, signal) {
46
+ async function* streamResponseInner(storage, params, syncParams, tracker, signal) {
48
47
  // Bucket state of bucket id -> op_id.
49
48
  // This starts with the state from the client. May contain buckets that the user do not have access to (anymore).
50
49
  let dataBuckets = new Map();
@@ -73,6 +72,11 @@ async function* streamResponseInner(storage, params, syncParams, signal) {
73
72
  parameters: syncParams
74
73
  });
75
74
  if (allBuckets.length > 1000) {
75
+ logger.error(`Too many buckets`, {
76
+ checkpoint,
77
+ user_id: syncParams.user_id,
78
+ buckets: allBuckets.length
79
+ });
76
80
  // TODO: Limit number of buckets even before we get to this point
77
81
  throw new Error(`Too many buckets: ${allBuckets.length}`);
78
82
  }
@@ -94,11 +98,18 @@ async function* streamResponseInner(storage, params, syncParams, signal) {
94
98
  continue;
95
99
  }
96
100
  bucketsToFetch = diff.updatedBuckets.map((c) => c.bucket);
97
- let message = `Updated checkpoint: ${checkpoint} | write: ${writeCheckpoint} | `;
101
+ let message = `Updated checkpoint: ${checkpoint} | `;
102
+ message += `write: ${writeCheckpoint} | `;
98
103
  message += `buckets: ${allBuckets.length} | `;
99
104
  message += `updated: ${limitedBuckets(diff.updatedBuckets, 20)} | `;
100
- message += `removed: ${limitedBuckets(diff.removedBuckets, 20)} | `;
101
- logger.info(message);
105
+ message += `removed: ${limitedBuckets(diff.removedBuckets, 20)}`;
106
+ logger.info(message, {
107
+ checkpoint,
108
+ user_id: syncParams.user_id,
109
+ buckets: allBuckets.length,
110
+ updated: diff.updatedBuckets.length,
111
+ removed: diff.removedBuckets.length
112
+ });
102
113
  const checksum_line = {
103
114
  checkpoint_diff: {
104
115
  last_op_id: checkpoint,
@@ -112,7 +123,7 @@ async function* streamResponseInner(storage, params, syncParams, signal) {
112
123
  else {
113
124
  let message = `New checkpoint: ${checkpoint} | write: ${writeCheckpoint} | `;
114
125
  message += `buckets: ${allBuckets.length} ${limitedBuckets(allBuckets, 20)}`;
115
- logger.info(message);
126
+ logger.info(message, { checkpoint, user_id: syncParams.user_id, buckets: allBuckets.length });
116
127
  bucketsToFetch = allBuckets;
117
128
  const checksum_line = {
118
129
  checkpoint: {
@@ -127,7 +138,16 @@ async function* streamResponseInner(storage, params, syncParams, signal) {
127
138
  lastWriteCheckpoint = writeCheckpoint;
128
139
  // This incrementally updates dataBuckets with each individual bucket position.
129
140
  // At the end of this, we can be sure that all buckets have data up to the checkpoint.
130
- yield* bucketDataInBatches({ storage, checkpoint, bucketsToFetch, dataBuckets, raw_data, binary_data, signal });
141
+ yield* bucketDataInBatches({
142
+ storage,
143
+ checkpoint,
144
+ bucketsToFetch,
145
+ dataBuckets,
146
+ raw_data,
147
+ binary_data,
148
+ signal,
149
+ tracker
150
+ });
131
151
  await new Promise((resolve) => setTimeout(resolve, 10));
132
152
  }
133
153
  }
@@ -168,7 +188,9 @@ async function* bucketDataInBatches(request) {
168
188
  * Extracted as a separate internal function just to avoid memory leaks.
169
189
  */
170
190
  async function* bucketDataBatch(request) {
171
- const { storage, checkpoint, bucketsToFetch, dataBuckets, raw_data, binary_data, signal } = request;
191
+ const { storage, checkpoint, bucketsToFetch, dataBuckets, raw_data, binary_data, tracker, signal } = request;
192
+ const checkpointOp = BigInt(checkpoint);
193
+ let checkpointInvalidated = false;
172
194
  const [_, release] = await syncSemaphore.acquire();
173
195
  try {
174
196
  // Optimization: Only fetch buckets for which the checksums have changed since the last checkpoint
@@ -176,13 +198,16 @@ async function* bucketDataBatch(request) {
176
198
  const filteredBuckets = new Map(bucketsToFetch.map((bucket) => [bucket, dataBuckets.get(bucket)]));
177
199
  const data = storage.getBucketDataBatch(checkpoint, filteredBuckets);
178
200
  let has_more = false;
179
- for await (let r of data) {
201
+ for await (let { batch: r, targetOp } of data) {
180
202
  if (signal.aborted) {
181
203
  return;
182
204
  }
183
205
  if (r.has_more) {
184
206
  has_more = true;
185
207
  }
208
+ if (targetOp != null && targetOp > checkpointOp) {
209
+ checkpointInvalidated = true;
210
+ }
186
211
  if (r.data.length == 0) {
187
212
  continue;
188
213
  }
@@ -213,16 +238,24 @@ async function* bucketDataBatch(request) {
213
238
  // iterator memory in case if large data sent.
214
239
  yield { data: null, done: false };
215
240
  }
216
- Metrics.getInstance().operations_synced_total.add(r.data.length);
241
+ tracker.addOperationsSynced(r.data.length);
217
242
  dataBuckets.set(r.bucket, r.next_after);
218
243
  }
219
244
  if (!has_more) {
220
- const line = {
221
- checkpoint_complete: {
222
- last_op_id: checkpoint
223
- }
224
- };
225
- yield { data: line, done: true };
245
+ if (checkpointInvalidated) {
246
+ // Checkpoint invalidated by a CLEAR or MOVE op.
247
+ // Don't send the checkpoint_complete line in this case.
248
+ // More data should be available immediately for a new checkpoint.
249
+ yield { data: null, done: true };
250
+ }
251
+ else {
252
+ const line = {
253
+ checkpoint_complete: {
254
+ last_op_id: checkpoint
255
+ }
256
+ };
257
+ yield { data: line, done: true };
258
+ }
226
259
  }
227
260
  }
228
261
  finally {
@@ -1 +1 @@
1
- {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/sync/sync.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/sync/sync.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
2
  /// <reference types="node" resolution-mode="require"/>
3
3
  import * as util from '../util/util-index.js';
4
+ import { RequestTracker } from './RequestTracker.js';
4
5
  export type TokenStreamOptions = {
5
6
  /**
6
7
  * Adds periodic keepalive events
@@ -23,4 +24,4 @@ export declare function tokenStream(token: {
23
24
  exp: number;
24
25
  }, signal: AbortSignal, options?: Partial<TokenStreamOptions>): AsyncGenerator<util.StreamingSyncKeepalive>;
25
26
  export declare function ndjson(iterator: AsyncIterable<string | null | Record<string, any>>): AsyncGenerator<string>;
26
- export declare function transformToBytesTracked(iterator: AsyncIterable<string>): AsyncGenerator<Buffer>;
27
+ export declare function transformToBytesTracked(iterator: AsyncIterable<string>, tracker: RequestTracker): AsyncGenerator<Buffer>;
package/dist/sync/util.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import * as timers from 'timers/promises';
2
- import { Metrics } from '../metrics/Metrics.js';
3
2
  const KEEPALIVE_INTERVAL = 20000;
4
3
  const DEFAULT_TOKEN_STREAM_OPTIONS = {
5
4
  keep_alive: true,
@@ -63,10 +62,10 @@ export async function* ndjson(iterator) {
63
62
  }
64
63
  }
65
64
  }
66
- export async function* transformToBytesTracked(iterator) {
65
+ export async function* transformToBytesTracked(iterator, tracker) {
67
66
  for await (let data of iterator) {
68
67
  const encoded = Buffer.from(data, 'utf8');
69
- Metrics.getInstance().data_synced_bytes.add(encoded.length);
68
+ tracker.addDataSynced(encoded.length);
70
69
  yield encoded;
71
70
  }
72
71
  }
@@ -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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"}
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
- "version": "0.0.0-dev-20240709124106",
8
+ "version": "0.0.0-dev-20240725112650",
9
9
  "main": "dist/index.js",
10
10
  "license": "FSL-1.1-Apache-2.0",
11
11
  "type": "module",
@@ -33,12 +33,12 @@
33
33
  "uuid": "^9.0.1",
34
34
  "winston": "^3.13.0",
35
35
  "yaml": "^2.3.2",
36
- "@powersync/lib-services-framework": "0.1.0",
36
+ "@powersync/lib-services-framework": "0.1.1",
37
+ "@powersync/service-jsonbig": "0.17.10",
38
+ "@powersync/service-rsocket-router": "0.0.10",
39
+ "@powersync/service-sync-rules": "0.18.1",
37
40
  "@powersync/service-jpgwire": "0.17.13",
38
- "@powersync/service-sync-rules": "0.0.0-dev-20240709124106",
39
- "@powersync/service-types": "0.1.0",
40
- "@powersync/service-rsocket-router": "0.0.8",
41
- "@powersync/service-jsonbig": "0.17.10"
41
+ "@powersync/service-types": "0.1.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/async": "^3.2.24",
@@ -3,7 +3,7 @@ import { Command } from 'commander';
3
3
  import * as utils from '../util/util-index.js';
4
4
  import { registerMigrationAction } from './commands/migrate-action.js';
5
5
  import { registerTearDownAction } from './commands/teardown-action.js';
6
- import { registerStartAction } from './entry-index.js';
6
+ import { registerCompactAction, registerStartAction } from './entry-index.js';
7
7
  import { logger } from '@powersync/lib-services-framework';
8
8
 
9
9
  /**
@@ -18,6 +18,7 @@ export function generateEntryProgram(startHandlers?: Record<utils.ServiceRunner,
18
18
 
19
19
  registerTearDownAction(entryProgram);
20
20
  registerMigrationAction(entryProgram);
21
+ registerCompactAction(entryProgram);
21
22
 
22
23
  if (startHandlers) {
23
24
  registerStartAction(entryProgram, startHandlers);
@@ -0,0 +1,54 @@
1
+ import { Command } from 'commander';
2
+
3
+ import { logger } from '@powersync/lib-services-framework';
4
+ import * as v8 from 'v8';
5
+ import { createPowerSyncMongo, MongoBucketStorage } from '../../storage/storage-index.js';
6
+ import { loadConfig } from '../../util/config.js';
7
+ import { extractRunnerOptions, wrapConfigCommand } from './config-command.js';
8
+
9
+ const COMMAND_NAME = 'compact';
10
+
11
+ /**
12
+ * Approximately max-old-space-size + 64MB.
13
+ */
14
+ const HEAP_LIMIT = v8.getHeapStatistics().heap_size_limit;
15
+
16
+ /**
17
+ * Subtract 128MB for process overhead.
18
+ *
19
+ * Limit to 1024MB overall.
20
+ */
21
+ const COMPACT_MEMORY_LIMIT_MB = Math.min(HEAP_LIMIT / 1024 / 1024 - 128, 1024);
22
+
23
+ export function registerCompactAction(program: Command) {
24
+ const compactCommand = program.command(COMMAND_NAME);
25
+
26
+ wrapConfigCommand(compactCommand);
27
+
28
+ return compactCommand.description('Compact storage').action(async (options) => {
29
+ const runnerConfig = extractRunnerOptions(options);
30
+
31
+ const config = await loadConfig(runnerConfig);
32
+ const { storage } = config;
33
+ const psdb = createPowerSyncMongo(storage);
34
+ const client = psdb.client;
35
+ await client.connect();
36
+ try {
37
+ const bucketStorage = new MongoBucketStorage(psdb, { slot_name_prefix: config.slot_name_prefix });
38
+ const active = await bucketStorage.getActiveSyncRules();
39
+ if (active == null) {
40
+ logger.info('No active instance to compact');
41
+ return;
42
+ }
43
+ const p = bucketStorage.getInstance(active);
44
+ await p.compact({ memoryLimitMB: COMPACT_MEMORY_LIMIT_MB });
45
+ logger.info('done');
46
+ } catch (e) {
47
+ logger.error(`Failed to compact: ${e.toString()}`);
48
+ process.exit(1);
49
+ } finally {
50
+ await client.close();
51
+ process.exit(0);
52
+ }
53
+ });
54
+ }
@@ -3,3 +3,4 @@ export * from './commands/config-command.js';
3
3
  export * from './commands/migrate-action.js';
4
4
  export * from './commands/start-action.js';
5
5
  export * from './commands/teardown-action.js';
6
+ export * from './commands/compact-action.js';
@@ -0,0 +1,102 @@
1
+ import type fastify from 'fastify';
2
+ import { registerFastifyRoutes } from './route-register.js';
3
+
4
+ import * as system from '../system/system-index.js';
5
+
6
+ import { ADMIN_ROUTES } from './endpoints/admin.js';
7
+ import { CHECKPOINT_ROUTES } from './endpoints/checkpointing.js';
8
+ import { DEV_ROUTES } from './endpoints/dev.js';
9
+ import { SYNC_RULES_ROUTES } from './endpoints/sync-rules.js';
10
+ import { SYNC_STREAM_ROUTES } from './endpoints/sync-stream.js';
11
+ import { createRequestQueueHook, CreateRequestQueueParams } from './hooks.js';
12
+ import { RouteDefinition } from './router.js';
13
+
14
+ /**
15
+ * A list of route definitions to be registered as endpoints.
16
+ * Supplied concurrency limits will be applied to the grouped routes.
17
+ */
18
+ export type RouteRegistrationOptions = {
19
+ routes: RouteDefinition[];
20
+ queueOptions: CreateRequestQueueParams;
21
+ };
22
+
23
+ /**
24
+ * HTTP routes separated by API and Sync stream categories.
25
+ * This allows for separate concurrency limits.
26
+ */
27
+ export type RouteDefinitions = {
28
+ api?: Partial<RouteRegistrationOptions>;
29
+ syncStream?: Partial<RouteRegistrationOptions>;
30
+ };
31
+
32
+ export type FastifyServerConfig = {
33
+ system: system.CorePowerSyncSystem;
34
+ routes?: RouteDefinitions;
35
+ };
36
+
37
+ export const DEFAULT_ROUTE_OPTIONS = {
38
+ api: {
39
+ routes: [...ADMIN_ROUTES, ...CHECKPOINT_ROUTES, ...DEV_ROUTES, ...SYNC_RULES_ROUTES],
40
+ queueOptions: {
41
+ concurrency: 10,
42
+ max_queue_depth: 20
43
+ }
44
+ },
45
+ syncStream: {
46
+ routes: [...SYNC_STREAM_ROUTES],
47
+ queueOptions: {
48
+ concurrency: 200,
49
+ max_queue_depth: 0
50
+ }
51
+ }
52
+ };
53
+
54
+ /**
55
+ * Registers default routes on a Fastify server. Consumers can optionally configure
56
+ * concurrency queue limits or override routes.
57
+ */
58
+ export function configureFastifyServer(server: fastify.FastifyInstance, options: FastifyServerConfig) {
59
+ const { system, routes = DEFAULT_ROUTE_OPTIONS } = options;
60
+ /**
61
+ * Fastify creates an encapsulated context for each `.register` call.
62
+ * Creating a separate context here to separate the concurrency limits for Admin APIs
63
+ * and Sync Streaming routes.
64
+ * https://github.com/fastify/fastify/blob/main/docs/Reference/Encapsulation.md
65
+ */
66
+ server.register(async function (childContext) {
67
+ registerFastifyRoutes(
68
+ childContext,
69
+ async () => {
70
+ return {
71
+ user_id: undefined,
72
+ system: system
73
+ };
74
+ },
75
+ routes.api?.routes ?? DEFAULT_ROUTE_OPTIONS.api.routes
76
+ );
77
+ // Limit the active concurrent requests
78
+ childContext.addHook(
79
+ 'onRequest',
80
+ createRequestQueueHook(routes.api?.queueOptions ?? DEFAULT_ROUTE_OPTIONS.api.queueOptions)
81
+ );
82
+ });
83
+
84
+ // Create a separate context for concurrency queueing
85
+ server.register(async function (childContext) {
86
+ registerFastifyRoutes(
87
+ childContext,
88
+ async () => {
89
+ return {
90
+ user_id: undefined,
91
+ system: system
92
+ };
93
+ },
94
+ routes.syncStream?.routes ?? DEFAULT_ROUTE_OPTIONS.syncStream.routes
95
+ );
96
+ // Limit the active concurrent requests
97
+ childContext.addHook(
98
+ 'onRequest',
99
+ createRequestQueueHook(routes.syncStream?.queueOptions ?? DEFAULT_ROUTE_OPTIONS.syncStream.queueOptions)
100
+ );
101
+ });
102
+ }
@@ -0,0 +1,59 @@
1
+ import { deserialize } from 'bson';
2
+ import * as http from 'http';
3
+
4
+ import { errors, logger } from '@powersync/lib-services-framework';
5
+ import { ReactiveSocketRouter, RSocketRequestMeta } from '@powersync/service-rsocket-router';
6
+
7
+ import { CorePowerSyncSystem } from '../system/CorePowerSyncSystem.js';
8
+ import { generateContext, getTokenFromHeader } from './auth.js';
9
+ import { syncStreamReactive } from './endpoints/socket-route.js';
10
+ import { RSocketContextMeta, SocketRouteGenerator } from './router-socket.js';
11
+ import { Context } from './router.js';
12
+
13
+ export type RSockerRouterConfig = {
14
+ system: CorePowerSyncSystem;
15
+ server: http.Server;
16
+ routeGenerators?: SocketRouteGenerator[];
17
+ };
18
+
19
+ export const DEFAULT_SOCKET_ROUTES = [syncStreamReactive];
20
+
21
+ export function configureRSocket(router: ReactiveSocketRouter<Context>, options: RSockerRouterConfig) {
22
+ const { routeGenerators = DEFAULT_SOCKET_ROUTES, server, system } = options;
23
+
24
+ router.applyWebSocketEndpoints(server, {
25
+ contextProvider: async (data: Buffer) => {
26
+ const { token } = RSocketContextMeta.decode(deserialize(data) as any);
27
+
28
+ if (!token) {
29
+ throw new errors.AuthorizationError('No token provided');
30
+ }
31
+
32
+ try {
33
+ const extracted_token = getTokenFromHeader(token);
34
+ if (extracted_token != null) {
35
+ const { context, errors: token_errors } = await generateContext(system, extracted_token);
36
+ if (context?.token_payload == null) {
37
+ throw new errors.AuthorizationError(token_errors ?? 'Authentication required');
38
+ }
39
+ return {
40
+ token,
41
+ ...context,
42
+ token_errors: token_errors,
43
+ system
44
+ };
45
+ } else {
46
+ throw new errors.AuthorizationError('No token provided');
47
+ }
48
+ } catch (ex) {
49
+ logger.error(ex);
50
+ throw ex;
51
+ }
52
+ },
53
+ endpoints: routeGenerators.map((generator) => generator(router)),
54
+ metaDecoder: async (meta: Buffer) => {
55
+ return RSocketRequestMeta.decode(deserialize(meta) as any);
56
+ },
57
+ payloadDecoder: async (rawData?: Buffer) => rawData && deserialize(rawData)
58
+ });
59
+ }
@@ -3,19 +3,13 @@ import { RequestParameters } from '@powersync/service-sync-rules';
3
3
  import { serialize } from 'bson';
4
4
 
5
5
  import { Metrics } from '../../metrics/Metrics.js';
6
- import { streamResponse } from '../../sync/sync.js';
6
+ import * as sync from '../../sync/sync-index.js';
7
7
  import * as util from '../../util/util-index.js';
8
8
  import { SocketRouteGenerator } from '../router-socket.js';
9
9
  import { SyncRoutes } from './sync-stream.js';
10
10
 
11
11
  export const syncStreamReactive: SocketRouteGenerator = (router) =>
12
12
  router.reactiveStream<util.StreamingSyncRequest, any>(SyncRoutes.STREAM, {
13
- authorize: ({ context }) => {
14
- return {
15
- authorized: !!context.token_payload,
16
- errors: ['Authentication required'].concat(context.token_errors ?? [])
17
- };
18
- },
19
13
  validator: schema.createTsCodecValidator(util.StreamingSyncRequest, { allowAdditional: true }),
20
14
  handler: async ({ context, params, responder, observer, initialN }) => {
21
15
  const { system } = context;
@@ -66,8 +60,9 @@ export const syncStreamReactive: SocketRouteGenerator = (router) =>
66
60
  });
67
61
 
68
62
  Metrics.getInstance().concurrent_connections.add(1);
63
+ const tracker = new sync.RequestTracker();
69
64
  try {
70
- for await (const data of streamResponse({
65
+ for await (const data of sync.streamResponse({
71
66
  storage,
72
67
  params: {
73
68
  ...params,
@@ -79,6 +74,7 @@ export const syncStreamReactive: SocketRouteGenerator = (router) =>
79
74
  // RSocket handles keepalive events by default
80
75
  keep_alive: false
81
76
  },
77
+ tracker,
82
78
  signal: controller.signal
83
79
  })) {
84
80
  if (data == null) {
@@ -94,7 +90,7 @@ export const syncStreamReactive: SocketRouteGenerator = (router) =>
94
90
  const serialized = serialize(data) as Buffer;
95
91
  responder.onNext({ data: serialized }, false);
96
92
  requestedN--;
97
- Metrics.getInstance().data_synced_bytes.add(serialized.length);
93
+ tracker.addDataSynced(serialized.length);
98
94
  }
99
95
 
100
96
  if (requestedN <= 0) {
@@ -126,6 +122,11 @@ export const syncStreamReactive: SocketRouteGenerator = (router) =>
126
122
  responder.onComplete();
127
123
  removeStopHandler();
128
124
  disposer();
125
+ logger.info(`Sync stream complete`, {
126
+ user_id: syncParams.user_id,
127
+ operations_synced: tracker.operationsSynced,
128
+ data_synced_bytes: tracker.dataSyncedBytes
129
+ });
129
130
  Metrics.getInstance().concurrent_connections.add(-1);
130
131
  }
131
132
  }
@@ -8,6 +8,7 @@ import * as util from '../../util/util-index.js';
8
8
  import { Metrics } from '../../metrics/Metrics.js';
9
9
  import { authUser } from '../auth.js';
10
10
  import { routeDefinition } from '../router.js';
11
+ import { RequestTracker } from '../../sync/RequestTracker.js';
11
12
 
12
13
  export enum SyncRoutes {
13
14
  STREAM = '/sync/stream'
@@ -43,6 +44,7 @@ export const syncStreamed = routeDefinition({
43
44
  });
44
45
  }
45
46
  const controller = new AbortController();
47
+ const tracker = new RequestTracker();
46
48
  try {
47
49
  Metrics.getInstance().concurrent_connections.add(1);
48
50
  const stream = Readable.from(
@@ -53,9 +55,11 @@ export const syncStreamed = routeDefinition({
53
55
  params,
54
56
  syncParams,
55
57
  token: payload.context.token_payload!,
58
+ tracker,
56
59
  signal: controller.signal
57
60
  })
58
- )
61
+ ),
62
+ tracker
59
63
  ),
60
64
  { objectMode: false, highWaterMark: 16 * 1024 }
61
65
  );
@@ -86,6 +90,11 @@ export const syncStreamed = routeDefinition({
86
90
  afterSend: async () => {
87
91
  controller.abort();
88
92
  Metrics.getInstance().concurrent_connections.add(-1);
93
+ logger.info(`Sync stream complete`, {
94
+ user_id: syncParams.user_id,
95
+ operations_synced: tracker.operationsSynced,
96
+ data_synced_bytes: tracker.dataSyncedBytes
97
+ });
89
98
  }
90
99
  });
91
100
  } catch (ex) {
@@ -1,6 +1,6 @@
1
- import fastify from 'fastify';
1
+ import type fastify from 'fastify';
2
2
 
3
- import { errors, router, HTTPMethod, logger } from '@powersync/lib-services-framework';
3
+ import { errors, HTTPMethod, logger, router } from '@powersync/lib-services-framework';
4
4
  import { Context, ContextProvider, RequestEndpoint, RequestEndpointHandlerPayload } from './router.js';
5
5
 
6
6
  export type FastifyEndpoint<I, O, C> = RequestEndpoint<I, O, C> & {
@@ -63,6 +63,7 @@ export function registerFastifyRoutes(
63
63
  }
64
64
  } catch (ex) {
65
65
  const journeyError = errors.JourneyError.isJourneyError(ex) ? ex : new errors.InternalServerError(ex);
66
+ logger.error(`Request failed`, journeyError);
66
67
 
67
68
  response = new router.RouterResponse({
68
69
  status: journeyError.errorData.status || 500,
@@ -1,13 +1,13 @@
1
+ import { IReactiveStream, ReactiveSocketRouter } from '@powersync/service-rsocket-router';
1
2
  import * as t from 'ts-codec';
2
- import { ReactiveSocketRouter, IReactiveStream } from '@powersync/service-rsocket-router';
3
3
 
4
4
  import { Context } from './router.js';
5
5
 
6
- export const RSocketContextMeta = t.object({
7
- token: t.string
8
- });
9
-
10
6
  /**
11
7
  * Creates a socket route handler given a router instance
12
8
  */
13
9
  export type SocketRouteGenerator = (router: ReactiveSocketRouter<Context>) => IReactiveStream;
10
+
11
+ export const RSocketContextMeta = t.object({
12
+ token: t.string
13
+ });
@@ -36,6 +36,8 @@ export type RequestEndpointHandlerPayload<
36
36
  request: Request;
37
37
  };
38
38
 
39
+ export type RouteDefinition<I = any, O = any> = RequestEndpoint<I, O>;
40
+
39
41
  /**
40
42
  * Helper function for making generics work well when defining routes
41
43
  */