@powerhousedao/reactor 6.0.0-dev.43 → 6.0.0-dev.44
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/dist/src/cache/kysely-operation-index.d.ts.map +1 -1
- package/dist/src/cache/kysely-operation-index.js +7 -2
- package/dist/src/cache/kysely-operation-index.js.map +1 -1
- package/dist/src/cache/operation-index-types.d.ts +2 -0
- package/dist/src/cache/operation-index-types.d.ts.map +1 -1
- package/dist/src/cache/operation-index-types.js.map +1 -1
- package/dist/src/executor/document-action-handler.d.ts +1 -1
- package/dist/src/executor/document-action-handler.d.ts.map +1 -1
- package/dist/src/executor/document-action-handler.js +16 -11
- package/dist/src/executor/document-action-handler.js.map +1 -1
- package/dist/src/executor/simple-job-executor.d.ts.map +1 -1
- package/dist/src/executor/simple-job-executor.js +32 -19
- package/dist/src/executor/simple-job-executor.js.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/storage/interfaces.d.ts +3 -1
- package/dist/src/storage/interfaces.d.ts.map +1 -1
- package/dist/src/storage/kysely/sync-cursor-storage.d.ts +1 -1
- package/dist/src/storage/kysely/sync-cursor-storage.d.ts.map +1 -1
- package/dist/src/storage/kysely/sync-cursor-storage.js +6 -2
- package/dist/src/storage/kysely/sync-cursor-storage.js.map +1 -1
- package/dist/src/storage/kysely/types.d.ts +2 -0
- package/dist/src/storage/kysely/types.d.ts.map +1 -1
- package/dist/src/storage/migrations/011_add_cursor_type_column.d.ts +3 -0
- package/dist/src/storage/migrations/011_add_cursor_type_column.d.ts.map +1 -0
- package/dist/src/storage/migrations/011_add_cursor_type_column.js +29 -0
- package/dist/src/storage/migrations/011_add_cursor_type_column.js.map +1 -0
- package/dist/src/storage/migrations/012_add_source_remote_column.d.ts +3 -0
- package/dist/src/storage/migrations/012_add_source_remote_column.d.ts.map +1 -0
- package/dist/src/storage/migrations/012_add_source_remote_column.js +7 -0
- package/dist/src/storage/migrations/012_add_source_remote_column.js.map +1 -0
- package/dist/src/storage/migrations/migrator.d.ts.map +1 -1
- package/dist/src/storage/migrations/migrator.js +4 -0
- package/dist/src/storage/migrations/migrator.js.map +1 -1
- package/dist/src/sync/batch-aggregator.d.ts +25 -0
- package/dist/src/sync/batch-aggregator.d.ts.map +1 -0
- package/dist/src/sync/batch-aggregator.js +94 -0
- package/dist/src/sync/batch-aggregator.js.map +1 -0
- package/dist/src/sync/buffered-mailbox.d.ts +14 -8
- package/dist/src/sync/buffered-mailbox.d.ts.map +1 -1
- package/dist/src/sync/buffered-mailbox.js +34 -6
- package/dist/src/sync/buffered-mailbox.js.map +1 -1
- package/dist/src/sync/channels/composite-channel-factory.d.ts +0 -6
- package/dist/src/sync/channels/composite-channel-factory.d.ts.map +1 -1
- package/dist/src/sync/channels/composite-channel-factory.js +4 -10
- package/dist/src/sync/channels/composite-channel-factory.js.map +1 -1
- package/dist/src/sync/channels/gql-channel-factory.js +2 -2
- package/dist/src/sync/channels/gql-channel-factory.js.map +1 -1
- package/dist/src/sync/channels/{gql-channel.d.ts → gql-req-channel.d.ts} +8 -27
- package/dist/src/sync/channels/gql-req-channel.d.ts.map +1 -0
- package/dist/src/sync/channels/{gql-channel.js → gql-req-channel.js} +142 -182
- package/dist/src/sync/channels/gql-req-channel.js.map +1 -0
- package/dist/src/sync/channels/gql-res-channel.d.ts +25 -0
- package/dist/src/sync/channels/gql-res-channel.d.ts.map +1 -0
- package/dist/src/sync/channels/gql-res-channel.js +79 -0
- package/dist/src/sync/channels/gql-res-channel.js.map +1 -0
- package/dist/src/sync/channels/index.d.ts +5 -5
- package/dist/src/sync/channels/index.d.ts.map +1 -1
- package/dist/src/sync/channels/index.js +5 -5
- package/dist/src/sync/channels/index.js.map +1 -1
- package/dist/src/sync/channels/utils.d.ts +15 -1
- package/dist/src/sync/channels/utils.d.ts.map +1 -1
- package/dist/src/sync/channels/utils.js +66 -2
- package/dist/src/sync/channels/utils.js.map +1 -1
- package/dist/src/sync/index.d.ts +6 -6
- package/dist/src/sync/index.d.ts.map +1 -1
- package/dist/src/sync/index.js +5 -5
- package/dist/src/sync/index.js.map +1 -1
- package/dist/src/sync/interfaces.d.ts +4 -18
- package/dist/src/sync/interfaces.d.ts.map +1 -1
- package/dist/src/sync/mailbox.d.ts +39 -18
- package/dist/src/sync/mailbox.d.ts.map +1 -1
- package/dist/src/sync/mailbox.js +50 -20
- package/dist/src/sync/mailbox.js.map +1 -1
- package/dist/src/sync/sync-manager.d.ts +5 -13
- package/dist/src/sync/sync-manager.d.ts.map +1 -1
- package/dist/src/sync/sync-manager.js +91 -275
- package/dist/src/sync/sync-manager.js.map +1 -1
- package/dist/src/sync/sync-operation.d.ts.map +1 -1
- package/dist/src/sync/sync-operation.js +3 -0
- package/dist/src/sync/sync-operation.js.map +1 -1
- package/dist/src/sync/types.d.ts +1 -0
- package/dist/src/sync/types.d.ts.map +1 -1
- package/dist/src/sync/types.js.map +1 -1
- package/dist/src/sync/utils.d.ts +18 -2
- package/dist/src/sync/utils.d.ts.map +1 -1
- package/dist/src/sync/utils.js +120 -1
- package/dist/src/sync/utils.js.map +1 -1
- package/package.json +3 -3
- package/dist/src/sync/channels/gql-channel.d.ts.map +0 -1
- package/dist/src/sync/channels/gql-channel.js.map +0 -1
- package/dist/src/sync/channels/polling-channel.d.ts +0 -39
- package/dist/src/sync/channels/polling-channel.d.ts.map +0 -1
- package/dist/src/sync/channels/polling-channel.js +0 -72
- package/dist/src/sync/channels/polling-channel.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mailbox.js","sourceRoot":"","sources":["../../../src/sync/mailbox.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mailbox.js","sourceRoot":"","sources":["../../../src/sync/mailbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { IOperationIndex } from "../cache/operation-index-types.js";
|
|
2
2
|
import type { IReactor } from "../core/types.js";
|
|
3
3
|
import type { IEventBus } from "../events/interfaces.js";
|
|
4
4
|
import type { ILogger } from "../logging/types.js";
|
|
@@ -17,13 +17,10 @@ export declare class SyncManager implements ISyncManager {
|
|
|
17
17
|
private readonly remotes;
|
|
18
18
|
private readonly awaiter;
|
|
19
19
|
private readonly syncAwaiter;
|
|
20
|
-
private readonly jobSyncStates;
|
|
21
20
|
private isShutdown;
|
|
22
21
|
private eventUnsubscribe?;
|
|
23
22
|
private failedEventUnsubscribe?;
|
|
24
|
-
private
|
|
25
|
-
private processingWriteReady;
|
|
26
|
-
private readonly pendingBatches;
|
|
23
|
+
private readonly batchAggregator;
|
|
27
24
|
loadJobs: Map<string, JobInfo>;
|
|
28
25
|
constructor(logger: ILogger, remoteStorage: ISyncRemoteStorage, cursorStorage: ISyncCursorStorage, channelFactory: IChannelFactory, operationIndex: IOperationIndex, reactor: IReactor, eventBus: IEventBus);
|
|
29
26
|
startup(): Promise<void>;
|
|
@@ -31,21 +28,16 @@ export declare class SyncManager implements ISyncManager {
|
|
|
31
28
|
getByName(name: string): Remote;
|
|
32
29
|
getById(id: string): Remote;
|
|
33
30
|
add(name: string, collectionId: string, channelConfig: ChannelConfig, filter?: RemoteFilter, options?: RemoteOptions, id?: string): Promise<Remote>;
|
|
34
|
-
private backfillOutbox;
|
|
35
31
|
remove(name: string): Promise<void>;
|
|
36
32
|
list(): Remote[];
|
|
37
33
|
waitForSync(jobId: string, signal?: AbortSignal): Promise<SyncResult>;
|
|
38
34
|
private wireChannelCallbacks;
|
|
39
|
-
private
|
|
40
|
-
private processWriteReadyQueue;
|
|
41
|
-
private handleWriteReadyAsync;
|
|
42
|
-
private handleJobFailedForBatch;
|
|
35
|
+
private getRemotesForCollection;
|
|
43
36
|
private processCompleteBatch;
|
|
44
37
|
private handleInboxAdded;
|
|
45
|
-
private handleOutboxJob;
|
|
46
38
|
private applyInboxJob;
|
|
47
39
|
private applyInboxBatch;
|
|
48
|
-
private
|
|
49
|
-
private
|
|
40
|
+
private updateOutbox;
|
|
41
|
+
private getOperationsForRemote;
|
|
50
42
|
}
|
|
51
43
|
//# sourceMappingURL=sync-manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-manager.d.ts","sourceRoot":"","sources":["../../../src/sync/sync-manager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sync-manager.d.ts","sourceRoot":"","sources":["../../../src/sync/sync-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EAGV,QAAQ,EACT,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAMzD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAEL,KAAK,OAAO,EACZ,KAAK,cAAc,EACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAG7E,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,aAAa,EAGb,UAAU,EACX,MAAM,YAAY,CAAC;AAUpB,qBAAa,WAAY,YAAW,YAAY;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAU;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IACnD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IACnD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAkB;IACjD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAkB;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAW;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAY;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,UAAU,CAAU;IAC5B,OAAO,CAAC,gBAAgB,CAAC,CAAa;IACtC,OAAO,CAAC,sBAAsB,CAAC,CAAa;IAC5C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAE3C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAa;gBAGhD,MAAM,EAAE,OAAO,EACf,aAAa,EAAE,kBAAkB,EACjC,aAAa,EAAE,kBAAkB,EACjC,cAAc,EAAE,eAAe,EAC/B,cAAc,EAAE,eAAe,EAC/B,OAAO,EAAE,QAAQ,EACjB,QAAQ,EAAE,SAAS;IAoBf,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA4D9B,QAAQ,IAAI,cAAc;IA8B1B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAQ/B,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IASrB,GAAG,CACP,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,aAAa,EAC5B,MAAM,GAAE,YAAwD,EAChE,OAAO,GAAE,aAA4C,EACrD,EAAE,CAAC,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC;IA0EZ,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBzC,IAAI,IAAI,MAAM,EAAE;IAIhB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAIrE,OAAO,CAAC,oBAAoB;IAuB5B,OAAO,CAAC,uBAAuB;YAMjB,oBAAoB;IAgClC,OAAO,CAAC,gBAAgB;YAyBV,aAAa;YA0Eb,eAAe;YAgFf,YAAY;YAmCZ,sBAAsB;CAyBrC"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { driveCollectionId, } from "../cache/operation-index-types.js";
|
|
2
1
|
import { ReactorEventTypes, } from "../events/types.js";
|
|
3
2
|
import { JobAwaiter } from "../shared/awaiter.js";
|
|
4
3
|
import { JobStatus, } from "../shared/types.js";
|
|
4
|
+
import { BatchAggregator } from "./batch-aggregator.js";
|
|
5
5
|
import { ChannelError } from "./errors.js";
|
|
6
6
|
import { SyncAwaiter } from "./sync-awaiter.js";
|
|
7
7
|
import { SyncOperation } from "./sync-operation.js";
|
|
8
|
-
import { ChannelErrorSource
|
|
9
|
-
import { batchOperationsByDocument, createIdleHealth, filterOperations, } from "./utils.js";
|
|
8
|
+
import { ChannelErrorSource } from "./types.js";
|
|
9
|
+
import { batchOperationsByDocument, createIdleHealth, filterOperations, toOperationWithContext, trimMailboxFromBatch, } from "./utils.js";
|
|
10
10
|
export class SyncManager {
|
|
11
11
|
logger;
|
|
12
12
|
remoteStorage;
|
|
@@ -18,13 +18,10 @@ export class SyncManager {
|
|
|
18
18
|
remotes;
|
|
19
19
|
awaiter;
|
|
20
20
|
syncAwaiter;
|
|
21
|
-
jobSyncStates;
|
|
22
21
|
isShutdown;
|
|
23
22
|
eventUnsubscribe;
|
|
24
23
|
failedEventUnsubscribe;
|
|
25
|
-
|
|
26
|
-
processingWriteReady = false;
|
|
27
|
-
pendingBatches = new Map();
|
|
24
|
+
batchAggregator;
|
|
28
25
|
loadJobs = new Map();
|
|
29
26
|
constructor(logger, remoteStorage, cursorStorage, channelFactory, operationIndex, reactor, eventBus) {
|
|
30
27
|
this.logger = logger;
|
|
@@ -37,8 +34,8 @@ export class SyncManager {
|
|
|
37
34
|
this.remotes = new Map();
|
|
38
35
|
this.awaiter = new JobAwaiter(eventBus, (jobId, signal) => reactor.getJobStatus(jobId, signal));
|
|
39
36
|
this.syncAwaiter = new SyncAwaiter(eventBus);
|
|
40
|
-
this.jobSyncStates = new Map();
|
|
41
37
|
this.isShutdown = false;
|
|
38
|
+
this.batchAggregator = new BatchAggregator(logger, (batch) => this.processCompleteBatch(batch));
|
|
42
39
|
}
|
|
43
40
|
async startup() {
|
|
44
41
|
if (this.isShutdown) {
|
|
@@ -47,13 +44,6 @@ export class SyncManager {
|
|
|
47
44
|
const remoteRecords = await this.remoteStorage.list();
|
|
48
45
|
for (const record of remoteRecords) {
|
|
49
46
|
const channel = this.channelFactory.instance(record.id, record.name, record.channelConfig, this.cursorStorage, record.collectionId, record.filter, this.operationIndex);
|
|
50
|
-
try {
|
|
51
|
-
await channel.init();
|
|
52
|
-
}
|
|
53
|
-
catch (error) {
|
|
54
|
-
console.error(`Error initializing channel for remote ${record.name}: ${error instanceof Error ? error.message : String(error)}`);
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
47
|
const remote = {
|
|
58
48
|
id: record.id,
|
|
59
49
|
name: record.name,
|
|
@@ -64,14 +54,26 @@ export class SyncManager {
|
|
|
64
54
|
};
|
|
65
55
|
this.remotes.set(record.name, remote);
|
|
66
56
|
this.wireChannelCallbacks(remote);
|
|
57
|
+
try {
|
|
58
|
+
await channel.init();
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
this.logger.error("Error initializing channel for remote (@name, @error)", record.name, error instanceof Error ? error.message : String(error));
|
|
62
|
+
this.remotes.delete(record.name);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
// backfill channels
|
|
66
|
+
const outboxAckOrdinal = remote.channel.outbox.ackOrdinal;
|
|
67
|
+
if (outboxAckOrdinal > 0) {
|
|
68
|
+
await this.updateOutbox(remote, outboxAckOrdinal);
|
|
69
|
+
}
|
|
67
70
|
}
|
|
68
|
-
this.eventUnsubscribe = this.eventBus.subscribe(ReactorEventTypes.JOB_WRITE_READY, (_type, event) => this.enqueueWriteReady(event));
|
|
69
|
-
this.failedEventUnsubscribe = this.eventBus.subscribe(ReactorEventTypes.JOB_FAILED, (_type, event) => this.
|
|
71
|
+
this.eventUnsubscribe = this.eventBus.subscribe(ReactorEventTypes.JOB_WRITE_READY, async (_type, event) => this.batchAggregator.enqueueWriteReady(event));
|
|
72
|
+
this.failedEventUnsubscribe = this.eventBus.subscribe(ReactorEventTypes.JOB_FAILED, async (_type, event) => this.batchAggregator.handleJobFailed(event));
|
|
70
73
|
}
|
|
71
74
|
shutdown() {
|
|
72
75
|
this.isShutdown = true;
|
|
73
|
-
this.
|
|
74
|
-
this.pendingBatches.clear();
|
|
76
|
+
this.batchAggregator.clear();
|
|
75
77
|
if (this.eventUnsubscribe) {
|
|
76
78
|
this.eventUnsubscribe();
|
|
77
79
|
this.eventUnsubscribe = undefined;
|
|
@@ -82,18 +84,14 @@ export class SyncManager {
|
|
|
82
84
|
}
|
|
83
85
|
this.awaiter.shutdown();
|
|
84
86
|
this.syncAwaiter.shutdown();
|
|
87
|
+
const promises = [];
|
|
85
88
|
for (const remote of this.remotes.values()) {
|
|
86
|
-
|
|
87
|
-
remote.channel.shutdown();
|
|
88
|
-
}
|
|
89
|
-
catch (error) {
|
|
90
|
-
console.error(`Error shutting down channel for remote ${remote.name}: ${error instanceof Error ? error.message : String(error)}`);
|
|
91
|
-
}
|
|
89
|
+
promises.push(remote.channel.shutdown());
|
|
92
90
|
}
|
|
93
91
|
this.remotes.clear();
|
|
94
92
|
return {
|
|
95
93
|
isShutdown: true,
|
|
96
|
-
completed: Promise.
|
|
94
|
+
completed: Promise.all(promises).then(() => undefined),
|
|
97
95
|
};
|
|
98
96
|
}
|
|
99
97
|
getByName(name) {
|
|
@@ -135,7 +133,6 @@ export class SyncManager {
|
|
|
135
133
|
};
|
|
136
134
|
await this.remoteStorage.upsert(remoteRecord);
|
|
137
135
|
const channel = this.channelFactory.instance(remoteId, name, channelConfig, this.cursorStorage, collectionId, filter, this.operationIndex);
|
|
138
|
-
await channel.init();
|
|
139
136
|
const remote = {
|
|
140
137
|
id: remoteId,
|
|
141
138
|
name,
|
|
@@ -146,55 +143,28 @@ export class SyncManager {
|
|
|
146
143
|
};
|
|
147
144
|
this.remotes.set(name, remote);
|
|
148
145
|
this.wireChannelCallbacks(remote);
|
|
149
|
-
await this.backfillOutbox(remote, collectionId, filter, options.sinceTimestampUtcMs);
|
|
150
|
-
return remote;
|
|
151
|
-
}
|
|
152
|
-
async backfillOutbox(remote, collectionId, filter, sinceTimestampUtcMs) {
|
|
153
|
-
let historicalOps;
|
|
154
146
|
try {
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
catch {
|
|
158
|
-
return;
|
|
147
|
+
await channel.init();
|
|
159
148
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
operation: {
|
|
165
|
-
id: entry.id,
|
|
166
|
-
index: entry.index,
|
|
167
|
-
skip: entry.skip,
|
|
168
|
-
hash: entry.hash,
|
|
169
|
-
timestampUtcMs: entry.timestampUtcMs,
|
|
170
|
-
action: entry.action,
|
|
171
|
-
},
|
|
172
|
-
context: {
|
|
173
|
-
documentId: entry.documentId,
|
|
174
|
-
documentType: entry.documentType,
|
|
175
|
-
scope: entry.scope,
|
|
176
|
-
branch: entry.branch,
|
|
177
|
-
ordinal: entry.ordinal ?? 0,
|
|
178
|
-
},
|
|
179
|
-
}));
|
|
180
|
-
let filteredOps = filterOperations(opsWithContext, filter);
|
|
181
|
-
filteredOps = filteredOps.filter((op) => op.operation.timestampUtcMs > sinceTimestampUtcMs);
|
|
182
|
-
if (filteredOps.length === 0) {
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
const batches = batchOperationsByDocument(filteredOps);
|
|
186
|
-
for (const batch of batches) {
|
|
187
|
-
const syncOp = new SyncOperation(crypto.randomUUID(), "", [], remote.name, batch.documentId, [batch.scope], batch.branch, batch.operations);
|
|
188
|
-
remote.channel.outbox.add(syncOp);
|
|
149
|
+
catch (error) {
|
|
150
|
+
this.remotes.delete(name);
|
|
151
|
+
await this.remoteStorage.remove(name);
|
|
152
|
+
throw error;
|
|
189
153
|
}
|
|
154
|
+
// backfill
|
|
155
|
+
await this.updateOutbox(remote, 0);
|
|
156
|
+
return remote;
|
|
190
157
|
}
|
|
191
158
|
async remove(name) {
|
|
192
159
|
const remote = this.remotes.get(name);
|
|
193
160
|
if (!remote) {
|
|
194
161
|
throw new Error(`Remote with name '${name}' does not exist`);
|
|
195
162
|
}
|
|
163
|
+
// shutdown the channel
|
|
164
|
+
await remote.channel.shutdown();
|
|
165
|
+
// delete the remote's data
|
|
196
166
|
await this.remoteStorage.remove(name);
|
|
197
|
-
|
|
167
|
+
await this.cursorStorage.remove(name);
|
|
198
168
|
this.remotes.delete(name);
|
|
199
169
|
}
|
|
200
170
|
list() {
|
|
@@ -204,168 +174,41 @@ export class SyncManager {
|
|
|
204
174
|
return this.syncAwaiter.waitForSync(jobId, signal);
|
|
205
175
|
}
|
|
206
176
|
wireChannelCallbacks(remote) {
|
|
207
|
-
remote.channel.inbox.onAdded((syncOps) =>
|
|
208
|
-
|
|
177
|
+
remote.channel.inbox.onAdded((syncOps) => this.handleInboxAdded(remote, syncOps));
|
|
178
|
+
remote.channel.outbox.onAdded(() => {
|
|
179
|
+
// todo: handle sync status updates
|
|
209
180
|
});
|
|
210
|
-
remote.channel.
|
|
181
|
+
remote.channel.deadLetter.onAdded((syncOps) => {
|
|
211
182
|
for (const syncOp of syncOps) {
|
|
212
|
-
this.
|
|
183
|
+
this.logger.error("Dead letter (@remote, @documentId, @jobId, @error, @dependencies)", remote.name, syncOp.documentId, syncOp.jobId, syncOp.error?.message ?? "unknown", syncOp.jobDependencies);
|
|
213
184
|
}
|
|
214
185
|
});
|
|
215
186
|
}
|
|
216
|
-
|
|
217
|
-
this.
|
|
218
|
-
void this.processWriteReadyQueue();
|
|
219
|
-
}
|
|
220
|
-
processWriteReadyQueue() {
|
|
221
|
-
if (this.processingWriteReady) {
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
this.processingWriteReady = true;
|
|
225
|
-
while (this.writeReadyQueue.length > 0) {
|
|
226
|
-
const event = this.writeReadyQueue.shift();
|
|
227
|
-
this.handleWriteReadyAsync(event);
|
|
228
|
-
}
|
|
229
|
-
this.processingWriteReady = false;
|
|
230
|
-
}
|
|
231
|
-
handleWriteReadyAsync(event) {
|
|
232
|
-
if (this.isShutdown) {
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
const { batchId, batchJobIds } = event.jobMeta;
|
|
236
|
-
if (batchJobIds.length <= 1) {
|
|
237
|
-
this.processCompleteBatch([event]);
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
let pending = this.pendingBatches.get(batchId);
|
|
241
|
-
if (!pending) {
|
|
242
|
-
pending = {
|
|
243
|
-
expectedJobIds: new Set(batchJobIds),
|
|
244
|
-
arrivedJobIds: new Set(),
|
|
245
|
-
events: [],
|
|
246
|
-
};
|
|
247
|
-
this.pendingBatches.set(batchId, pending);
|
|
248
|
-
}
|
|
249
|
-
pending.arrivedJobIds.add(event.jobId);
|
|
250
|
-
pending.events.push(event);
|
|
251
|
-
if (pending.arrivedJobIds.size >= pending.expectedJobIds.size) {
|
|
252
|
-
this.pendingBatches.delete(batchId);
|
|
253
|
-
this.processCompleteBatch(pending.events);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
handleJobFailedForBatch(event) {
|
|
257
|
-
if (this.isShutdown) {
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
const batchId = event.job?.meta.batchId;
|
|
261
|
-
if (!batchId) {
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
const pending = this.pendingBatches.get(batchId);
|
|
265
|
-
if (!pending) {
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
this.pendingBatches.delete(batchId);
|
|
269
|
-
if (pending.events.length > 0) {
|
|
270
|
-
void this.processCompleteBatch(pending.events);
|
|
271
|
-
}
|
|
187
|
+
getRemotesForCollection(collectionId) {
|
|
188
|
+
return Array.from(this.remotes.values()).filter((remote) => remote.collectionId === collectionId);
|
|
272
189
|
}
|
|
273
|
-
processCompleteBatch(
|
|
274
|
-
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
for (const op of event.operations) {
|
|
290
|
-
const action = op.operation.action;
|
|
291
|
-
if (action.type !== "ADD_RELATIONSHIP") {
|
|
292
|
-
continue;
|
|
293
|
-
}
|
|
294
|
-
const input = action.input;
|
|
295
|
-
if (!input?.sourceId || !input.targetId) {
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
298
|
-
const collectionId = driveCollectionId(op.context.branch, input.sourceId);
|
|
299
|
-
if (!(input.targetId in mergedMemberships)) {
|
|
300
|
-
mergedMemberships[input.targetId] = [];
|
|
301
|
-
}
|
|
302
|
-
if (!mergedMemberships[input.targetId].includes(collectionId)) {
|
|
303
|
-
mergedMemberships[input.targetId].push(collectionId);
|
|
190
|
+
async processCompleteBatch(batch) {
|
|
191
|
+
// get the unique set of collection ids
|
|
192
|
+
const collectionIds = [
|
|
193
|
+
...new Set(Object.values(batch.collectionMemberships).flatMap((collections) => collections)),
|
|
194
|
+
];
|
|
195
|
+
// get the unique set of affected remotes
|
|
196
|
+
const affectedRemotes = [];
|
|
197
|
+
for (const collectionId of collectionIds) {
|
|
198
|
+
const remotes = this.getRemotesForCollection(collectionId);
|
|
199
|
+
for (const remote of remotes) {
|
|
200
|
+
if (!affectedRemotes.includes(remote)) {
|
|
201
|
+
affectedRemotes.push(remote);
|
|
304
202
|
}
|
|
305
203
|
}
|
|
306
204
|
}
|
|
307
|
-
|
|
308
|
-
for (const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
continue;
|
|
315
|
-
}
|
|
316
|
-
let filteredOps = filterOperations(event.operations, remote.filter);
|
|
317
|
-
if (filteredOps.length === 0) {
|
|
318
|
-
continue;
|
|
319
|
-
}
|
|
320
|
-
// If remote has empty documentId filter, it means "sync all docs in this collection"
|
|
321
|
-
// In this case, we need to filter by collection membership
|
|
322
|
-
if (remote.filter.documentId.length === 0) {
|
|
323
|
-
filteredOps = this.filterByCollectionMembership(filteredOps, remote.collectionId, mergedMemberships);
|
|
324
|
-
if (filteredOps.length === 0) {
|
|
325
|
-
continue;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
const batches = batchOperationsByDocument(filteredOps);
|
|
329
|
-
for (const batch of batches) {
|
|
330
|
-
const syncOp = new SyncOperation(crypto.randomUUID(), event.jobId, isBatch ? [...priorJobIds] : [], remote.name, batch.documentId, [batch.scope], batch.branch, batch.operations);
|
|
331
|
-
syncOpsWithRemote.push({ syncOp, remote });
|
|
332
|
-
if (!remoteNames.includes(remote.name)) {
|
|
333
|
-
remoteNames.push(remote.name);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
if (syncOpsWithRemote.length > 0 && event.jobId) {
|
|
338
|
-
this.jobSyncStates.set(event.jobId, {
|
|
339
|
-
total: syncOpsWithRemote.length,
|
|
340
|
-
completed: new Set(),
|
|
341
|
-
failed: new Map(),
|
|
342
|
-
remoteNames,
|
|
343
|
-
});
|
|
344
|
-
const pendingEvent = {
|
|
345
|
-
jobId: event.jobId,
|
|
346
|
-
syncOperationCount: syncOpsWithRemote.length,
|
|
347
|
-
remoteNames,
|
|
348
|
-
};
|
|
349
|
-
void this.eventBus.emit(SyncEventTypes.SYNC_PENDING, pendingEvent);
|
|
350
|
-
}
|
|
351
|
-
for (const { syncOp, remote } of syncOpsWithRemote) {
|
|
352
|
-
syncOp.on((op, _prev, next) => {
|
|
353
|
-
if (next === SyncOperationStatus.Applied) {
|
|
354
|
-
this.markSyncOpCompleted(op.jobId, op.id, true);
|
|
355
|
-
}
|
|
356
|
-
else if (next === SyncOperationStatus.Error) {
|
|
357
|
-
this.markSyncOpCompleted(op.jobId, op.id, false, {
|
|
358
|
-
remoteName: op.remoteName,
|
|
359
|
-
documentId: op.documentId,
|
|
360
|
-
error: op.error?.message ?? "Unknown error",
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
});
|
|
364
|
-
remote.channel.outbox.add(syncOp);
|
|
365
|
-
}
|
|
366
|
-
if (isBatch && event.jobId) {
|
|
367
|
-
priorJobIds.push(event.jobId);
|
|
368
|
-
}
|
|
205
|
+
// ack matching inbox items
|
|
206
|
+
for (const remote of affectedRemotes) {
|
|
207
|
+
trimMailboxFromBatch(remote.channel.inbox, batch);
|
|
208
|
+
}
|
|
209
|
+
// finally, work through the affected remotes and backfill based on the last operation in the outbox
|
|
210
|
+
for (const remote of affectedRemotes) {
|
|
211
|
+
await this.updateOutbox(remote, remote.channel.outbox.latestOrdinal);
|
|
369
212
|
}
|
|
370
213
|
}
|
|
371
214
|
handleInboxAdded(remote, syncOps) {
|
|
@@ -389,16 +232,6 @@ export class SyncManager {
|
|
|
389
232
|
void this.applyInboxBatch(keyed.map((syncOp) => ({ remote, syncOp })));
|
|
390
233
|
}
|
|
391
234
|
}
|
|
392
|
-
handleOutboxJob(remote, syncOp) {
|
|
393
|
-
syncOp.on((syncOp, _prev, next) => {
|
|
394
|
-
if (next === SyncOperationStatus.Applied) {
|
|
395
|
-
remote.channel.outbox.remove(syncOp);
|
|
396
|
-
}
|
|
397
|
-
else if (next === SyncOperationStatus.Error) {
|
|
398
|
-
remote.channel.outbox.remove(syncOp);
|
|
399
|
-
}
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
235
|
async applyInboxJob(remote, syncOp) {
|
|
403
236
|
const operations = syncOp.operations.map((op) => op.operation);
|
|
404
237
|
let jobInfo;
|
|
@@ -449,7 +282,7 @@ export class SyncManager {
|
|
|
449
282
|
scope: syncOp.scopes[0],
|
|
450
283
|
branch: syncOp.branch,
|
|
451
284
|
operations: syncOp.operations.map((op) => op.operation),
|
|
452
|
-
dependsOn: syncOp.jobDependencies,
|
|
285
|
+
dependsOn: syncOp.jobDependencies.filter(Boolean),
|
|
453
286
|
}));
|
|
454
287
|
const request = { jobs };
|
|
455
288
|
let result;
|
|
@@ -469,6 +302,11 @@ export class SyncManager {
|
|
|
469
302
|
}
|
|
470
303
|
for (const { remote, syncOp } of items) {
|
|
471
304
|
if (!(syncOp.jobId in result.jobs)) {
|
|
305
|
+
this.logger.error("Job key missing from batch load result (@remote, @documentId, @jobId)", remote.name, syncOp.documentId, syncOp.jobId);
|
|
306
|
+
const error = new ChannelError(ChannelErrorSource.Inbox, new Error(`Job key '${syncOp.jobId}' missing from batch load result`));
|
|
307
|
+
syncOp.failed(error);
|
|
308
|
+
remote.channel.deadLetter.add(syncOp);
|
|
309
|
+
remote.channel.inbox.remove(syncOp);
|
|
472
310
|
continue;
|
|
473
311
|
}
|
|
474
312
|
const jobInfo = result.jobs[syncOp.jobId];
|
|
@@ -497,55 +335,33 @@ export class SyncManager {
|
|
|
497
335
|
remote.channel.inbox.remove(syncOp);
|
|
498
336
|
}
|
|
499
337
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
}
|
|
504
|
-
const state = this.jobSyncStates.get(jobId);
|
|
505
|
-
if (!state) {
|
|
338
|
+
async updateOutbox(remote, ackOrdinal) {
|
|
339
|
+
const operations = await this.getOperationsForRemote(remote, ackOrdinal);
|
|
340
|
+
if (operations.length === 0) {
|
|
506
341
|
return;
|
|
507
342
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
const succeededEvent = {
|
|
518
|
-
jobId,
|
|
519
|
-
syncOperationCount: state.total,
|
|
520
|
-
};
|
|
521
|
-
void this.eventBus.emit(SyncEventTypes.SYNC_SUCCEEDED, succeededEvent);
|
|
522
|
-
}
|
|
523
|
-
else {
|
|
524
|
-
const failedEvent = {
|
|
525
|
-
jobId,
|
|
526
|
-
successCount: state.completed.size,
|
|
527
|
-
failureCount: state.failed.size,
|
|
528
|
-
errors: Array.from(state.failed.values()),
|
|
529
|
-
};
|
|
530
|
-
void this.eventBus.emit(SyncEventTypes.SYNC_FAILED, failedEvent);
|
|
531
|
-
}
|
|
532
|
-
this.jobSyncStates.delete(jobId);
|
|
343
|
+
// create sync operations, each batch has a dependency on the previous one
|
|
344
|
+
const batches = batchOperationsByDocument(operations);
|
|
345
|
+
let prevJobId;
|
|
346
|
+
const syncOps = [];
|
|
347
|
+
for (const batch of batches) {
|
|
348
|
+
const jobId = crypto.randomUUID();
|
|
349
|
+
const syncOp = new SyncOperation(crypto.randomUUID(), jobId, prevJobId ? [prevJobId] : [], remote.name, batch.documentId, [batch.scope], batch.branch, batch.operations);
|
|
350
|
+
syncOps.push(syncOp);
|
|
351
|
+
prevJobId = jobId;
|
|
533
352
|
}
|
|
353
|
+
remote.channel.outbox.add(...syncOps);
|
|
534
354
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
//
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
return false;
|
|
546
|
-
}
|
|
547
|
-
return collectionMemberships[documentId].includes(collectionId);
|
|
548
|
-
});
|
|
355
|
+
async getOperationsForRemote(remote, ackOrdinal) {
|
|
356
|
+
const results = await this.operationIndex.find(remote.collectionId, ackOrdinal, { excludeSourceRemote: remote.name });
|
|
357
|
+
let operations = results.results.map((entry) => toOperationWithContext(entry));
|
|
358
|
+
// apply the sinceTimestampUtcMs filter
|
|
359
|
+
const sinceTimestamp = remote.options.sinceTimestampUtcMs;
|
|
360
|
+
if (sinceTimestamp && sinceTimestamp !== "0") {
|
|
361
|
+
operations = operations.filter((op) => op.operation.timestampUtcMs >= sinceTimestamp);
|
|
362
|
+
}
|
|
363
|
+
// apply the remote filter
|
|
364
|
+
return filterOperations(operations, remote.filter);
|
|
549
365
|
}
|
|
550
366
|
}
|
|
551
367
|
//# sourceMappingURL=sync-manager.js.map
|