Fix race condition in session transactions
This commit is contained in:
parent
227f532ec2
commit
4a6132933c
2 changed files with 40 additions and 3 deletions
|
@ -625,10 +625,21 @@ export class SignalProtocolStore extends EventsMixin {
|
||||||
window.log.info(
|
window.log.info(
|
||||||
`${debugName}: locked by ${this.currentZone.name}, waiting`
|
`${debugName}: locked by ${this.currentZone.name}, waiting`
|
||||||
);
|
);
|
||||||
await new Promise<void>(resolve => this.zoneQueue.push(resolve));
|
|
||||||
|
|
||||||
const duration = Date.now() - start;
|
return new Promise<T>((resolve, reject) => {
|
||||||
window.log.info(`${debugName}: unlocked after ${duration}ms`);
|
this.zoneQueue.push(async () => {
|
||||||
|
const duration = Date.now() - start;
|
||||||
|
window.log.info(`${debugName}: unlocked after ${duration}ms`);
|
||||||
|
|
||||||
|
// Call `.withZone` synchronously from `this.zoneQueue` to avoid
|
||||||
|
// extra in-between ticks while we are on microtasks queue.
|
||||||
|
try {
|
||||||
|
resolve(await this.withZone(zone, name, body));
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.enterZone(zone, name);
|
this.enterZone(zone, name);
|
||||||
|
|
|
@ -1384,6 +1384,32 @@ describe('SignalProtocolStore', () => {
|
||||||
|
|
||||||
assert.equal(await store.loadSession(id), testRecord);
|
assert.equal(await store.loadSession(id), testRecord);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can be re-entered after waiting', async () => {
|
||||||
|
const a = new Zone('a');
|
||||||
|
const b = new Zone('b');
|
||||||
|
|
||||||
|
const order: Array<number> = [];
|
||||||
|
const promises: Array<Promise<unknown>> = [];
|
||||||
|
|
||||||
|
// What happens below is briefly following:
|
||||||
|
// 1. We enter zone "a"
|
||||||
|
// 2. We wait for zone "a" to be left to enter zone "b"
|
||||||
|
// 3. Skip few ticks to trigger leave of zone "a" and resolve the waiting
|
||||||
|
// queue promise for zone "b"
|
||||||
|
// 4. Enter zone "a" while resolution was the promise above is queued in
|
||||||
|
// microtasks queue.
|
||||||
|
|
||||||
|
promises.push(store.withZone(a, 'a', async () => order.push(1)));
|
||||||
|
promises.push(store.withZone(b, 'b', async () => order.push(2)));
|
||||||
|
await Promise.resolve();
|
||||||
|
await Promise.resolve();
|
||||||
|
promises.push(store.withZone(a, 'a again', async () => order.push(3)));
|
||||||
|
|
||||||
|
await Promise.all(promises);
|
||||||
|
|
||||||
|
assert.deepEqual(order, [1, 2, 3]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Not yet processed messages', () => {
|
describe('Not yet processed messages', () => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue