Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

router does not await async functions #358

Closed
mtkage opened this issue Jun 6, 2017 · 15 comments
Closed

router does not await async functions #358

mtkage opened this issue Jun 6, 2017 · 15 comments

Comments

@mtkage
Copy link

mtkage commented Jun 6, 2017

Hi

I am using the following versions
nodejs v7.7.1
+-- koa@2.2.0
+-- koa-router@7.2.0

My problem is that the router returns without awaiting for the async function to resolve. The sample code is below:

router.get('/relay', async (ctx) => {
  const token = await relay();
  ctx.status = 200;
  ctx.body = token;
});

async function relay() {
  return await timeout(5000);
}

async function timeout(delay) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("random");
    }, delay);
  });
};

I can see from my logs that the route /relay returns immediately with a 404. The timeout function is called asynchronously and when it tries to set the ctx status the following error is thrown.
AssertionError: headers have already been sent

There does not seem to be a clear way to achieve what I want. I simply want to await an asynchronous function and return once it is resolved. How can I do this?

@jbielick
Copy link
Collaborator

Here's a test case I created on my machine with
node 7.8
koa 2.2
koa-router 7.2

const Koa = require('koa');
const Router = require('koa-router');

const app = new Koa();
const router = new Router();

router.get('/relay', async (ctx) => {
  const token = await relay();
  ctx.status = 200;
  ctx.body = token;
});

async function relay() {
  return await timeout(5000);
}

async function timeout(delay) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("random");
    }, delay);
  });
};

app.use(router.routes());

app.listen(3001);

And it seems to work fine:

┌[josh@HAL9000] [7]
└[~]> time curl localhost:3001/relay
random
curl localhost:3001/relay  0.00s user 0.00s system 0% cpu 5.030 total

Is this a representative sample of the code where you're having the issue?

@mtkage
Copy link
Author

mtkage commented Jun 10, 2017

Yes. It does seem to be representative of my code. And it is working on my machine as well. Let me take another look at the code. I must be doing something wrong with the middlewares. Thanks for your time and help!

@mtkage mtkage closed this as completed Jun 10, 2017
@crcrcry
Copy link

crcrcry commented Jul 7, 2017

How did you solve the problem?

@ccsang
Copy link

ccsang commented Aug 7, 2017

@mtkage I meet the problem too, could you tell me how you fixed it? Thanks a lot.

@mtkage
Copy link
Author

mtkage commented Aug 7, 2017

@crcrcry @ccsang The problem usually lies in the code that you must be calling. When using async await, you need to make sure that the entire call stack uses the same paradigm. If any of the functions in the stack do not await an async function, the desired result is not seen.

Check if you are using some external libraries that might be triggering functions asynchronously.

@ccsang
Copy link

ccsang commented Aug 8, 2017

@mtkage I examined my middlewares, finally found out the mistake I made as you said, thanks.

@wzdxy
Copy link

wzdxy commented Dec 9, 2017

I also encountered a similar problem. I got a 404 error as long as I called an asynchronous function in the route. But if I don't call any asynchronous function, there's no problem
The reason is that one of a middlewares does not use the await modifier when calling the next() method. ( Even if it doesn't seem to have anything to do with the router )
I guess this may cause the middleware to continue executing without waiting for the return result of the next middleware.
eg:

// this is wrong
app.use(function (ctx, next) {
    ctx.set("Access-Control-Allow-Origin", "*");
    next();
});
// this is right
app.use(async function (ctx, next) {
    ctx.set("Access-Control-Allow-Origin", "*");
    await next();
});

@a932455223
Copy link

@mtkage I meet the problem too,thank you

@rosshadden
Copy link

This is such a weird problem because the workaround that @wzdxy posted doesn't seem like it should even be related. But it does fix it.

@jbielick
Copy link
Collaborator

jbielick commented Apr 9, 2018

@rosshadden you need to either await next(); or return next(); otherwise Koa has no idea that you're doing something async and your function won't wait on downstream middleware.

@rosshadden
Copy link

Haha I just had the realization that it actually makes perfect sense and came back here to update accordingly. But you beat me to it.

@MoSofi
Copy link

MoSofi commented Jun 30, 2018

@wzdxy @jbielick you guys saved my day

@Oyelaking
Copy link

@mtkage @wzdxy Thanks guys! This has been giving me a headache all day. After reading the comments, I went and found the middleware that wasn't an Async function. Geez! A whole freaking day spent on this!

@liweijian1
Copy link

@mtkage @wzdxy Thanks guys!

@daGaiGuanYu
Copy link

You must await all the next()!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests