Account for provider config weight when kicking off a request in FallbackProvider (#4298).
This commit is contained in:
parent
e2485b8ef9
commit
da34e3569e
@ -4,6 +4,7 @@ import {
|
|||||||
isError, makeError,
|
isError, makeError,
|
||||||
|
|
||||||
AbstractProvider, FallbackProvider, Network,
|
AbstractProvider, FallbackProvider, Network,
|
||||||
|
ZeroAddress
|
||||||
} from "../index.js";
|
} from "../index.js";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
@ -93,3 +94,68 @@ describe("Test Fallback broadcast", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Test Inflight Quorum", function() {
|
||||||
|
// Fires the %%actions%% as providers which will delay before returning,
|
||||||
|
// and returns an array of arrays, where each sub-array indicates which
|
||||||
|
// providers were inflight at once.
|
||||||
|
async function test(actions: Array<{ delay: number, stallTimeout: number, priority: number, weight: number }>, quorum: number): Promise<Array<Array<number>>> {
|
||||||
|
const inflights: Array<Array<number>> = [ [ ] ];
|
||||||
|
|
||||||
|
const configs = actions.map(({ delay, stallTimeout, priority, weight }, index) => ({
|
||||||
|
provider: new MockProvider(async (r) => {
|
||||||
|
if (r.method === "getBlockNumber") { return 1; }
|
||||||
|
if (r.method === "getBalance") {
|
||||||
|
// Add this as inflight
|
||||||
|
let last = inflights.pop();
|
||||||
|
if (last == null) { throw new Error("no elements"); }
|
||||||
|
inflights.push(last);
|
||||||
|
last = last.slice();
|
||||||
|
last.push(index);
|
||||||
|
inflights.push(last);
|
||||||
|
|
||||||
|
// Do the thing
|
||||||
|
await stall(delay);
|
||||||
|
|
||||||
|
// Remove as inflight
|
||||||
|
last = inflights.pop();
|
||||||
|
if (last == null) { throw new Error("no elements"); }
|
||||||
|
inflights.push(last);
|
||||||
|
last = last.filter((v) => (v !== index));
|
||||||
|
inflights.push(last);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
console.log(r);
|
||||||
|
throw new Error(`unhandled method: ${ r.method }`);
|
||||||
|
}),
|
||||||
|
stallTimeout, priority, weight
|
||||||
|
}));
|
||||||
|
|
||||||
|
const provider = new FallbackProvider(configs, network, {
|
||||||
|
cacheTimeout: -1, pollingInterval: 100,
|
||||||
|
quorum
|
||||||
|
});
|
||||||
|
await provider.getBalance(ZeroAddress);
|
||||||
|
|
||||||
|
return inflights;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See: #4298
|
||||||
|
it("applies weights against inflight requests", async function() {
|
||||||
|
this.timeout(2000);
|
||||||
|
|
||||||
|
const inflights = await test([
|
||||||
|
{ delay: 50, stallTimeout: 1000, priority: 1, weight: 2 },
|
||||||
|
{ delay: 50, stallTimeout: 1000, priority: 1, weight: 2 },
|
||||||
|
], 2);
|
||||||
|
|
||||||
|
// Make sure there is never more than 1 inflight provider at once
|
||||||
|
for (const running of inflights) {
|
||||||
|
assert.ok(running.length <= 1, `too many inflight requests: ${ JSON.stringify(inflights) }`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// @TODO: add lots more tests, checking on priority, weight and stall
|
||||||
|
// configurations
|
||||||
|
});
|
||||||
|
@ -684,7 +684,7 @@ export class FallbackProvider extends AbstractProvider {
|
|||||||
// Add any new runners, because a staller timed out or a result
|
// Add any new runners, because a staller timed out or a result
|
||||||
// or error response came in.
|
// or error response came in.
|
||||||
for (let i = 0; i < newRunners; i++) {
|
for (let i = 0; i < newRunners; i++) {
|
||||||
this.#addRunner(running, req)
|
this.#addRunner(running, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
// All providers have returned, and we have no result
|
// All providers have returned, and we have no result
|
||||||
@ -759,8 +759,12 @@ export class FallbackProvider extends AbstractProvider {
|
|||||||
|
|
||||||
// Bootstrap enough runners to meet quorum
|
// Bootstrap enough runners to meet quorum
|
||||||
const running: Set<RunnerState> = new Set();
|
const running: Set<RunnerState> = new Set();
|
||||||
for (let i = 0; i < this.quorum; i++) {
|
let inflightQuorum = 0;
|
||||||
this.#addRunner(running, req);
|
while (true) {
|
||||||
|
const runner = this.#addRunner(running, req);
|
||||||
|
if (runner == null) { break; }
|
||||||
|
inflightQuorum += runner.config.weight;
|
||||||
|
if (inflightQuorum >= this.quorum) { break; }
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await this.#waitForQuorum(running, req);
|
const result = await this.#waitForQuorum(running, req);
|
||||||
|
Loading…
Reference in New Issue
Block a user