Skip to content

Commit

Permalink
sync engine level replaces interval when called again
Browse files Browse the repository at this point in the history
  • Loading branch information
LiranCohen committed Sep 4, 2024
1 parent 4527444 commit 4d95c0c
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 11 deletions.
42 changes: 31 additions & 11 deletions packages/agent/src/sync-engine-level.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export class SyncEngineLevel implements SyncEngine {

private _db: AbstractLevel<string | Buffer | Uint8Array>;
private _syncIntervalId?: ReturnType<typeof setInterval>;
private _syncLock = false;
private _ulidFactory: ULIDFactory;

constructor({ agent, dataPath, db }: SyncEngineLevelParams) {
Expand Down Expand Up @@ -268,11 +269,23 @@ export class SyncEngineLevel implements SyncEngine {
throw new Error('SyncEngineLevel: Cannot call sync while a sync interval is active. Call `stopSync()` first.');
}

if (!direction || direction === 'push') {
await this.push();
if (this._syncLock) {
throw new Error('SyncEngineLevel: Cannot call sync while a sync operation is in progress.');

Check warning on line 273 in packages/agent/src/sync-engine-level.ts

View check run for this annotation

Codecov / codecov/patch

packages/agent/src/sync-engine-level.ts#L273

Added line #L273 was not covered by tests
}
if (!direction || direction === 'pull') {
await this.pull();

try {
this._syncLock = true;
if (!direction || direction === 'push') {
await this.push();
}
if (!direction || direction === 'pull') {
await this.pull();
}
} catch (error: any) {
this._syncLock = false;
throw error;

Check warning on line 286 in packages/agent/src/sync-engine-level.ts

View check run for this annotation

Codecov / codecov/patch

packages/agent/src/sync-engine-level.ts#L285-L286

Added lines #L285 - L286 were not covered by tests
} finally {
this._syncLock = false;
}
}

Expand All @@ -283,24 +296,31 @@ export class SyncEngineLevel implements SyncEngine {
const intervalMilliseconds = ms(interval);

return new Promise((resolve, reject) => {

const intervalSync = async () => {
if (this._syncIntervalId) {
clearInterval(this._syncIntervalId);
if (this._syncLock) {
return;

Check warning on line 301 in packages/agent/src/sync-engine-level.ts

View check run for this annotation

Codecov / codecov/patch

packages/agent/src/sync-engine-level.ts#L301

Added line #L301 was not covered by tests
}

// clears the interval and sets the syncIntervalId to undefined
this.stopSync();

try {
await this.push();
await this.pull();
await this.sync();
} catch (error: any) {
this.stopSync();
reject(error);
}

// then we start sync again
this._syncIntervalId = setInterval(intervalSync, intervalMilliseconds);
if (!this._syncIntervalId) {
// only set a new interval if none is set. The most recently called `startSync` will set the final interval.
this._syncIntervalId = setInterval(intervalSync, intervalMilliseconds);
}
};

if (this._syncIntervalId) {
clearInterval(this._syncIntervalId);
}

this._syncIntervalId = setInterval(intervalSync, intervalMilliseconds);
});
}
Expand Down
43 changes: 43 additions & 0 deletions packages/agent/tests/sync-engine-level.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2473,6 +2473,49 @@ describe('SyncEngineLevel', () => {
pushSpy.restore();
clock.restore();
});

it('calls sync once per interval with the latest interval timer being respected', async () => {
await testHarness.agent.sync.registerIdentity({
did: alice.did.uri,
});

const clock = sinon.useFakeTimers();

const syncSpy = sinon.stub(SyncEngineLevel.prototype as any, 'sync');
// set to be a sync time longer than the interval
syncSpy.returns(new Promise<void>((resolve) => {
clock.setTimeout(() => {
resolve();
}, 1_000);
}));

testHarness.agent.sync.startSync({ interval: '500ms' });

await clock.tickAsync(1_400); // less than the initial interval + the sync time

expect(syncSpy.callCount).to.equal(1);

// set to be a short sync time
syncSpy.returns(new Promise<void>((resolve) => {
clock.setTimeout(() => {
resolve();
}, 15);
}));

testHarness.agent.sync.startSync({ interval: '300ms' });

await clock.tickAsync(301); // exactly the new interval + 1

expect(syncSpy.callCount).to.equal(2);


await clock.tickAsync(601); // two more intervals

expect(syncSpy.callCount).to.equal(4);

syncSpy.restore();
clock.restore();
});
});
});
});

0 comments on commit 4d95c0c

Please sign in to comment.