Search code examples
prisma-graphqlnexus-prismaprisma2

Why nexus dev command runs app twice, and how to fix it?


I created super simple application using nexus graphql framework.

First step like this:

https://www.nexusjs.org/#/tutorial/chapter-1-setup-and-first-query

I api/app.ts i typed code:

const uid = require('uid')

let i = 0;

const sleep = async (ms: number) => {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, ms)
    })
}

const recurrenceFunction = async (id:string): Promise<void> => {
    i++;
    console.log(id, i);
    await sleep(2000);
    return recurrenceFunction(id)
}

const startQueue = () => {
    const id:string = uid();
    return recurrenceFunction(id)
}

(async () => {
    return startQueue()
})()

Only dependency is uid that generates unique keys.

When I run it with ts-node I can see:

enter image description here

So we can see:

  1. Once queue started.
  2. There is single queue.
  3. It works as it should work.

But when I run this code with nexus by command nexus dev I have seen:

enter image description here

So:

  1. Two queues started.
  2. They are running at the same time.
  3. They have independently created variables i.

Questions:

  • Is anyone meet with this problem?
  • How should I change my code to get single queue like in ts-node?
  • Or maybe it is bug of nexus?

Update:

I checked that this problem exists for verions >= 0.21.1-next.2

In 0.21.1-next.1 application runs single time.

Steps to reproduce:

nexus dev
npm i nexus@0.21.1-next.1
nexus dev
npm i nexus@0.21.1-next.2

there is commit that introduced this behavior:

https://github.com/graphql-nexus/nexus/commit/ce1d45359e33af81169b7ebdc7bee6718fe313a8

There is variables like onMainThread and REFLECTION_ENV_VAR but without references to documentation. I can't understand what this code is doing?

This probably will be documented in future in this place:

https://www.nexusjs.org/#/architecture?id=build-flow

but now there is:

enter image description here

Update 2

I found woraround:

const xid = uid();
let limit=10;
const onApplicationStart = async (cb: () => any):Promise<any> => {
    console.log("can i start?", xid, limit, app.private.state.running);
    if(app.private.state.running) {
        await cb()
        return;
    }
    limit--;
    if(limit <= 0) return ;
    await sleep(100);
    return onApplicationStart(cb);
}

(async () => {

    return onApplicationStart(async () => {
        return startQueue()
    })

})()

but this is rather temporary hack than solution. Full example:

https://github.com/graphql-nexus/nexus/discussions/983


Solution

  • Eager module code relying on side-effects is not supported by Nexus.

    See:

    For a workaround for now wrap your code like this:

    // app.ts
    if (!process.env.NEXUS_REFLECTION) {
      yourHeavyAsyncCode()
    }
    

    Reference https://github.com/graphql-nexus/nexus/issues/732#issuecomment-626586244