jsumners/fastify-server-session

Redirect Hangs when using Abstract cache use await

zekth opened this issue · 9 comments

zekth commented

When using the useAwait parameter set to true and doing a reply.redirect() the reply hangs and is never fullfilled.

Here is the example snippet:

const fastify = require('fastify');
const IORedis = require('ioredis');
const fastifyCaching = require('fastify-caching');
const fastifyCookie = require('fastify-cookie');
const fastifySession = require('fastify-server-session');
const AbCache = require('abstract-cache');

const app = fastify({ logger: true });
const redisClient = new IORedis({
  host: '127.0.0.1',
  port: 6379
});
const abache = AbCache({
  useAwait: true,
  driver: {
    name: 'abstract-cache-redis',
    options: { client: redisClient }
  }
});
app
  .register(fastifyCookie)
  .register(fastifyCaching, {
    expiresIn: 50,
    cache: abache,
    cacheSegment: 'fastifyCache'
  })
  .register(fastifySession, {
    sessionCookieName: 'KA-SESSION',
    secretKey: '01010101111001110100101010100010101',
    sessionMaxAge: 1000 * 60 * 60 * 24 * 7, // 1 week
    cookie: { path: '/', httpOnly: true, sameSite: 'None', secure: true }
  });
app.get('/redirect', async function (req, rep) {
  return rep.redirect('https://www.fastify.io/'); // Hangs and never reply
});
app.listen(3001, '0.0.0.0', (err) => {
  if (err) console.error(err);
});

Dependencies:

{
  "dependencies": {
    "abstract-cache": "1.0.1",
    "abstract-cache-redis": "2.0.0",
    "fastify": "3.17.0",
    "fastify-caching": "6.1.0",
    "fastify-cookie": "5.3.1",
    "fastify-server-session": "4.0.0",
    "ioredis": "4.27.3"
  }
}
zekth commented

This might be the reason:
https://github.com/fastify/fastify/blob/28b92c15f8a4898128ab1443de429316c2d1b430/lib/reply.js#L303

redirect is a void and it's not returning the reply. Is there a reason why there is no return in here?

I don't know. It's going to be some time before I can run the reproduction through a debugger to see what the issue is.

zekth commented

After investigation seems that using useAwait the this.cache.get is never called here:

this.cache.get(sessionId, (err, cached) => {

Sorry if i can't provide better inputs

I am unable to replicate this. I copied and pasted the replication, ran docker run --rm -it -p 6369:6379 redis, and hit the server:

❯ curl -v 127.0.0.1:3001/redirect
*   Trying 127.0.0.1:3001...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 3001 (#0)
> GET /redirect HTTP/1.1
> Host: 127.0.0.1:3001
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 Found
< location: https://www.fastify.io/
< content-length: 0
< Date: Sun, 20 Jun 2021 12:09:47 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< 
* Connection #0 to host 127.0.0.1 left intact
*

The plugin hits this code path and returns control to Fastify:

if (req.session[syms.kSessionModified] === false) {
return hookFinished()
}

zekth commented

I'll give it a shot asap. I remember having this issue even without the redirect. I'll setup a proper example.

zekth commented

@jsumners my example was bad because it was not mutating the session. Please use this route

app.get('/redirect', async function (req, rep) {
  req.session.touched = true
  return rep.redirect('https://www.fastify.io/'); // Hangs and never reply
});
zekth commented

Seems like issue comes from fastify-caching : fastify/fastify-caching#75

I saw that. I still haven't been able to get back to debugging it.

zekth commented

Fixed in #17