-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Description
Prerequisites
- I have written a descriptive issue title
- I have searched existing issues to ensure the bug has not already been reported
Fastify version
3.27.2
Plugin version
N/A
Node.js version
14.18.1
Operating system
macOS
Operating system version (i.e. 20.04, 11.3, 10)
12.2.1
Description
I suspect this may actually be a bug in avvio, but logging it here since it's easily reproduced in a Fastify server startup sequence.
We have a handful of Fastify plugins with async registration functions. Our app registers them sequentially via code like:
await fastify.register(asyncPlugin1);
await fastify.register(asyncPlugin2);
await fastify.register(asyncPlugin3);
We're running into an interesting issue where if we inject some async code in between the plugin register calls (e.g., await someOtherAsyncFunc()), the subsequent promises returned by fastify.register() appear to be resolved immediately without waiting for internal async registration promises to be resolved.
Steps to Reproduce
- Clone this repo: https://github.com/chrskrchr/fastify-plugin-race-condition
- Run
npm install - Run
node index.js
Alternatively, run this code yourself:
import Fastify from "fastify";
function sleep(timeMs){
return new Promise((resolve) => setTimeout(resolve, timeMs));
}
(async () => {
const fastify = Fastify({
logger: true,
});
await fastify.register(async function plugin0() {
console.log("plugin0 register start");
console.log("plugin0 register finish");
});
await fastify.register(async function plugin1() {
console.log("plugin1 register start");
await sleep(500);
console.log("plugin1 register finish");
});
await sleep(1);
await fastify.register(async function plugin2() {
console.log("plugin2 register start");
await sleep(500);
console.log("plugin2 register finish");
});
console.log("starting server");
await fastify.listen(3000);
})();
Expected Behavior
We'd expect to see the following output where all plugins complete registration prior to the server being started:
plugin0 register start
plugin0 register finish
plugin1 register start
plugin1 register finish
plugin2 register start
plugin2 register finish
starting server
{"level":30,"time":1645638489287,"pid":13851,"hostname":"AUS-CKARCHER","msg":"Server listening at http://127.0.0.1:3000"}
Instead, we see the following output where the server is started prior to plugin2 actually completing its async registration:
plugin0 register start
plugin0 register finish
plugin1 register start
plugin1 register finish
plugin2 register start
starting server
plugin2 register finish
{"level":30,"time":1645638594807,"pid":13905,"hostname":"AUS-CKARCHER","msg":"Server listening at http://127.0.0.1:3000"}