Fix syncing when network latency is present (#4)

* WIP

* Add debug

* Dedupe inserts

* Add deterministic ordering

* Fix whitespaces

* Update insta

* Add integration test script

* Rename

* Add test

* Working for non-deletes

* omg it mostly works for deletes

* Isdeleted fix

* remove created dates

* update api

* Take document id

* No max attempt

* works

* Use string uuids

* .

* working!!!! (hopefully)

* Improve bundling

* Add module

* lint

* .

* lint

* Fix CI

* use toolchain

* clean up

* Add useSlowFileEvents

* Delete fuzz

* Fix CI

* use docker

* fix script

* clean up

* Clean up

* change node version

* Build docker image on every commit

* fix ci

* 1 db per vault

* Add scritps folder

* Bump versions

* Lint

* .

* Fix tests for real

* Style

* .

* try

* Consistent ordering

* Fix tests

* hmm

* .

* Clean up diff

* Fixes

* .

* Fix version bump

* .

* .

* .
This commit is contained in:
Andras Schmelczer 2025-03-16 20:13:49 +00:00 committed by GitHub
parent bcf48c428d
commit 8b8f1d91d9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
91 changed files with 2252 additions and 1586 deletions

View file

@ -3,20 +3,26 @@ import { MockAgent } from "./agent/mock-agent";
import { sleep } from "./utils/sleep";
import { v4 as uuidv4 } from "uuid";
let slowFileEvents = false;
async function runTest({
agentCount,
concurrency,
iterations,
doDeletes,
useSlowFileEvents,
jitterScaleInSeconds
}: {
agentCount: number;
concurrency: number;
iterations: number;
doDeletes: boolean;
useSlowFileEvents: boolean;
jitterScaleInSeconds: number;
}): Promise<void> {
const settings = `with ${agentCount} agents, concurrency ${concurrency}, iterations ${iterations}, doDeletes ${doDeletes}, jitterScaleInSeconds ${jitterScaleInSeconds}`;
slowFileEvents = useSlowFileEvents;
const settings = `with ${agentCount} agents, concurrency ${concurrency}, iterations ${iterations}, doDeletes ${doDeletes}, jitterScaleInSeconds ${jitterScaleInSeconds}, useSlowFileEvents ${useSlowFileEvents}`;
console.info(`Running test ${settings}`);
const initialSettings: Partial<SyncSettings> = {
@ -34,6 +40,7 @@ async function runTest({
initialSettings,
`agent-${i}`,
doDeletes,
useSlowFileEvents,
jitterScaleInSeconds
)
);
@ -52,12 +59,24 @@ async function runTest({
// Each agent can have unpushed changes which might conflict with eachother so each has to resolve the conflicts & push, and
for (const client of clients) {
await client.finish();
try {
await client.finish();
} catch (err) {
if (!slowFileEvents) {
throw err;
}
}
}
// then we need a second pass to ensure that all agents pull the same state.
for (const client of clients) {
await client.finish();
try {
await client.finish();
} catch (err) {
if (!slowFileEvents) {
throw err;
}
}
}
console.info("Agents finished successfully");
@ -78,41 +97,49 @@ async function runTest({
console.info(`Content check for ${client.name} passed`);
});
console.info(`Test passed with ${settings}`);
console.info(`Test passed ${settings}`);
} catch (err) {
console.error(`Test failed with ${settings}`);
console.error(`Test failed ${settings}`);
throw err;
}
}
async function runTests(): Promise<void> {
const agentCounts = [2, 10];
const jitterScaleInSeconds = [0.5, 3, 0];
const concurrencies = [1, 16];
const iterations = [50, 300];
const doDeletes = [false, true];
for (const agentCount of agentCounts) {
for (const concurrency of concurrencies) {
for (const jitter of jitterScaleInSeconds) {
for (const iteration of iterations) {
for (const deleteFiles of doDeletes) {
while (true) {
await runTest({
agentCount,
concurrency,
iterations: iteration,
doDeletes: deleteFiles,
jitterScaleInSeconds: jitter
});
}
}
}
for (const useSlowFileEvents of [false, true]) {
for (const concurrency of [
16,
1 // test with concurrency 1 to check for deadlocks
]) {
for (const doDeletes of [true, false]) {
await runTest({
agentCount: 3,
concurrency,
iterations: 100,
doDeletes,
useSlowFileEvents,
jitterScaleInSeconds: 0.75
});
}
}
}
}
process.on("uncaughtException", (error) => {
if (slowFileEvents) {
return;
}
console.error("Uncaught Exception:", error);
process.exit(1);
});
process.on("unhandledRejection", (reason, _promise) => {
if (slowFileEvents) {
return;
}
console.error("Unhandled Rejection:", reason);
process.exit(1);
});
runTests()
.then(() => {
process.exit(0);