nestjs / nest

A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications with TypeScript/JavaScript 🚀
https://nestjs.com
MIT License
66.9k stars 7.55k forks source link

RedisIoAdapter - Application Hangs when Initializing Redis-backed WebSocket Adapter #12090

Closed Kareszrk closed 1 year ago

Kareszrk commented 1 year ago

Is there an existing issue for this?

Current behavior

When attempting to initialize a Redis-backed WebSocket adapter with the following lines:

const redisIoAdapter = new RedisIoAdapter(app);
await redisIoAdapter.connectToRedis();
app.useWebSocketAdapter(redisIoAdapter);

the application hangs and does not complete execution. So I was wondering why that can happen, so I tried to put try catch around this, hoping to see an error, but it never showed any.

try {
  await redisIoAdapter.connectToRedis();
} catch (error) {
  console.error('Failed to connect to Redis:', error);
  process.exit(1);
}

Any help on this issue would be greatly appreciated.

It just stops executing my NestJS project. Basically stops at this part: [2:43:37 PM] File change detected. Starting incremental compilation...

[2:43:38 PM] Found 0 errors. Watching for file changes.

[Nest] 231 - 07/20/2023, 2:43:39 PM LOG [NestFactory] Starting Nest application... [Nest] 231 - 07/20/2023, 2:43:39 PM LOG [InstanceLoader] EventsModule dependencies initialized +38ms [Nest] 231 - 07/20/2023, 2:43:39 PM LOG [InstanceLoader] ThrottlerModule dependencies initialized +0ms [Nest] 231 - 07/20/2023, 2:43:39 PM LOG [InstanceLoader] ConfigHostModule dependencies initialized +0ms [Nest] 231 - 07/20/2023, 2:43:39 PM LOG [InstanceLoader] ConfigModule dependencies initialized +1ms [Nest] 231 - 07/20/2023, 2:43:39 PM LOG [InstanceLoader] AppModule dependencies initialized +1ms

Minimum reproduction code

https://github.com/nestjs/nest/tree/master/sample/02-gateways

Steps to reproduce

Just basically insert these files to a NestJS project, which is built on Express. https://github.com/nestjs/nest/tree/master/sample/02-gateways

Expected behavior

The expected behavior when running these two lines of code:

await redisIoAdapter.connectToRedis();
app.useWebSocketAdapter(redisIoAdapter);

is that the RedisIoAdapter instance redisIoAdapter should establish a successful connection to the Redis server through the connectToRedis method. If the connection is successful, the Redis server would then act as a backing store for WebSocket connections in my application.

Then, the useWebSocketAdapter method sets the redisIoAdapter as the adapter for handling WebSocket connections in my NestJS application. This means that the NestJS application would use this adapter to manage all WebSocket connections, including broadcasting messages to clients.

In the context of a running application, this would mean that after these lines of code are executed, the application should be able to handle WebSocket connections and broadcast messages to clients using Redis as a store. This would be crucial since I need this application compatible with load-balancers. And after many many research I found out this could be the right solution to this. If a client makes a WebSocket connection request to the server, the server should be able to accept the connection, handle any messages sent over the connection, and also broadcast messages to multiple clients if needed.

Since the application hangs or does not complete execution, it indicates that there is a problem with setting up the WebSocket adapter.

The link I provided in "steps to reproduce" is basically the same as what I have, I just copy pasted them and I have modified the redis link. VSCode did not show any errors, so technically there shouldn't be any problem.

Package

Other package

No response

NestJS version

10.0.2

Packages versions

{
  "name": "first",
  "version": "0.0.1",
  "description": "",
  "author": "",
  "private": true,
  "license": "UNLICENSED",
  "scripts": {
    "prebuild": "rimraf dist",
    "build": "nest build",
    "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
    "start": "nest start",
    "start:dev": "nest start --watch",
    "start:debug": "nest start --debug --watch",
    "start:prod": "node dist/main",
    "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:cov": "jest --coverage",
    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
    "test:e2e": "jest --config ./test/jest-e2e.json"
  },
  "dependencies": {
    "@nestjs/cache-manager": "^2.1.0",
    "@nestjs/common": "^10.0.1",
    "@nestjs/config": "^3.0.0",
    "@nestjs/core": "^10.0.1",
    "@nestjs/passport": "^10.0.0",
    "@nestjs/platform-express": "^10.0.1",
    "@nestjs/platform-socket.io": "^10.0.1",
    "@nestjs/throttler": "^4.1.0",
    "@nestjs/websockets": "^10.0.1",
    "@socket.io/redis-adapter": "^8.2.1",
    "@types/speakeasy": "^2.0.7",
    "aws-sdk": "^2.1399.0",
    "bcrypt": "^5.1.0",
    "cors": "^2.8.5",
    "cross-fetch": "^3.1.6",
    "crypto-js": "^4.1.1",
    "express-fileupload": "^1.4.0",
    "express-handlebars": "^7.0.7",
    "express-mysql-session": "^3.0.0",
    "express-session": "^1.17.3",
    "fs": "^0.0.1-security",
    "hbs": "^4.2.0",
    "jsonschema": "^1.4.1",
    "mysql2": "^3.3.5",
    "nodemailer": "^6.9.3",
    "nodemon": "^2.0.22",
    "passport": "^0.6.0",
    "passport-github2": "^0.1.12",
    "passport-google-oauth2": "^0.2.0",
    "passport-google-oauth20": "^2.0.0",
    "passport-local": "^1.0.0",
    "qrcode": "^1.5.3",
    "redis": "^4.6.7",
    "reflect-metadata": "^0.1.13",
    "request-ip": "^3.3.0",
    "rimraf": "^3.0.2",
    "sharp": "^0.32.1",
    "socket.io": "^4.7.1",
    "socket.io-client": "^4.7.1",
    "speakeasy": "^2.0.0"
  },
  "devDependencies": {
    "@nestjs/cli": "^10.0.2",
    "@nestjs/schematics": "^10.0.1",
    "@nestjs/testing": "^10.0.1",
    "@types/express": "^4.17.17",
    "@types/express-session": "^1.17.7",
    "@types/jest": "29.5.2",
    "@types/node": "^20.3.1",
    "@types/passport-local": "^1.0.35",
    "@types/request-ip": "^0.0.38",
    "@types/supertest": "^2.0.12",
    "@typescript-eslint/eslint-plugin": "^5.0.0",
    "@typescript-eslint/parser": "^5.59.11",
    "eslint": "^8.43.0",
    "eslint-config-prettier": "^8.8.0",
    "eslint-plugin-prettier": "^4.2.1",
    "jest": "29.5.0",
    "prettier": "^2.8.8",
    "source-map-support": "^0.5.21",
    "supertest": "^6.3.3",
    "ts-jest": "29.1.0",
    "ts-loader": "^9.4.3",
    "ts-node": "^10.9.1",
    "tsconfig-paths": "4.2.0",
    "typescript": "^5.1.3"
  },
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      "ts"
    ],
    "rootDir": "src",
    "testRegex": ".*\\.spec\\.ts$",
    "transform": {
      "^.+\\.(t|j)s$": "ts-jest"
    },
    "collectCoverageFrom": [
      "**/*.(t|j)s"
    ],
    "coverageDirectory": "../coverage",
    "testEnvironment": "node"
  }
}

Node.js version

18.17 (Dockerized, image: node:18)

In which operating systems have you tested?

Other

Without these lines:

await redisIoAdapter.connectToRedis();
app.useWebSocketAdapter(redisIoAdapter);

The console looks like this: (perfect, but websockets don't work)

https://kepkuldes.com/images/a3bacd06c8d794954ac599edebbbfba0.png

With the mentioned lines, it looks like this:

(and never continues, no matter how much time has passed since start) https://kepkuldes.com/images/bbf65778b2af7f621e88d7b92fa5a6ef.png

Most probably the redis URL I pass has no problems, since if I provide it badly an error appears in the console telling me time out or incorrect url. The link contains the password and the redis user as well.

(Similar like this

rediss://username:my_imagined_password@db-redis-fra1-42834-do-user-13041738-0.b.db.ondigitalocean.com:25061

)

I would point out that if I try as of how digitalocean suggests me this link, so rediss instead of redis it just times out, so I modified it in my code to have redis:// etc...

I attached you my main.ts file here. (renamed to txt because of github limitation) main.txt

kamilmysliwiec commented 1 year ago

Please, use our Discord channel (support) for such questions. We are using GitHub to track bugs, feature requests, and potential improvements.