从打字稿到 postgres 的连接挂起

Fah*_*ari 3 postgresql typescript sequelize-typescript

我正在尝试从打字稿连接到 Postgres 数据库。我sequelize-typescript用作 ORM。我的问题是脚本卡在await sequelize.sync();. 这是sequelize.ts文件:

import {Sequelize} from 'sequelize-typescript';
import { config } from './config/config';


const c = config.dev;

// Instantiate new Sequelize instance!
export const sequelize = new Sequelize({
  "username": c.username,
  "password": c.password,
  "database": c.database,
  "host":     c.host,

  dialect: 'postgres',
  storage: ':memory:',
});
Run Code Online (Sandbox Code Playgroud)

这是模型类文件Product.ts

  import {Table, Column, Model, HasMany, PrimaryKey, CreatedAt, UpdatedAt, ForeignKey} from 'sequelize-typescript';

@Table
export class Product extends Model<Product> {

    @Column
    public brand: string;

    @Column
    public price: number;

    @Column
    public description!: string;

    @Column
    public imgUrl!: string;

    @Column
    public cateogry: string;

  
}
Run Code Online (Sandbox Code Playgroud)

这是server.ts我使用 sequelize 的地方:

    (async () => {
 

  
  await sequelize.addModels(V0MODELS);

  //It get's stuck here
  await sequelize.sync();

  const app = express();
  const port =  8100; // default port to listen
  
  app.use(bodyParser.json());

  
  app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "http://localhost:8100");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
    next();
  });

  app.use('/api/v0/', IndexRouter);

  // Root URI call
  app.get( "/", async ( req, res ) => {
    res.send( "/api/v0/" );
  } );
  

  // Start the Server
  app.listen( port, () => {
      console.log( `server running http://localhost:${ port }` );
      console.log( `press CTRL+C to stop server, please :)` );
  } );
})();
Run Code Online (Sandbox Code Playgroud)

这是package.json内容:

{
  "name": "bagsshoes-server",
  "version": "1.0.0",
  "description": "",
  "main": "src/server.js",
  "scripts": {
    "start": "node .",
    "tsc": "tsc",
    "dev": "ts-node-dev --respawn --transpile-only ./src/server.ts",
    "prod": "tsc && node ./www/server.js",
    "clean": "rd /s /q www/>nul 2>&1|echo.>nul",
    "build": "npm run clean && tsc && cp -rf src/config www/config && cp .npmrc www/.npmrc && cp package.json www/package.json && cd www && zip -r Archive.zip . && cd ..",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "Fahima Mokhtari",
  "license": "ISC",
  "dependencies": {
    "@types/bcrypt": "^3.0.0",
    "@types/jsonwebtoken": "^8.3.2",
    "bcrypt": "^3.0.6",
    "body-parser": "^1.19.0",
    "email-validator": "^2.0.4",
    "express": "^4.17.1",
    "jsonwebtoken": "^8.5.1",
    "pg": "^7.9.0",
    "reflect-metadata": "^0.1.13",
    "sequelize": "^5.3.5",
    "sequelize-typescript": "^0.6.9"
  },
  "devDependencies": {
    "@types/bluebird": "^3.5.27",
    "@types/express": "^4.17.0",
    "@types/node": "^11.13.17",
    "@types/sequelize": "^4.27.44",
    "@types/validator": "^10.11.1",
    "chai": "^4.2.0",
    "chai-http": "^4.3.0",
    "mocha": "^6.1.4",
    "ts-node-dev": "^1.0.0-pre.40",
    "tslint": "^5.18.0",
    "typescript": "^3.5.3"
  }
}
Run Code Online (Sandbox Code Playgroud)

我试过了trycatch但没有显示任何错误,这让我更加困惑。任何帮助将不胜感激!

PS:

我正在使用 Windows 和 Node V14.7.0

Moh*_*lal 13

注意

顶级域名!(脱脂时间太长)!答案又长又丰富!你可以略读!它的格式很好!

如果你很着急!您可以检查Authenticate部分、Sequelize-typescript (not sequelize)部分、Sequelize-typescript部分。

更好的你可以直接去地狱节!了解 nodejs v14地狱!(直接走到最后!好一点以上)。

也检查一下FIX (Postgres v14 HELL)

我开始了,不知不觉我发现自己写的太多了!

超级指南

基本上续集不应该只是挂!但是抛出错误!

查看代码源

通过查看这里的sync代码

 async sync(options) {
    // ...

    // no models defined, just authenticate
    if (!models.length) {
      await this.authenticate(options);
    } else {
      for (const model of models) await model.sync(options);
    }
    if (options.hooks) {
      await this.runHooks('afterBulkSync', options);
    }
    return this;
  }
Run Code Online (Sandbox Code Playgroud)

人们很容易就能看到悬挂的可能性!

日志记录

要调试此类异常首先重要的是要有良好的日志记录

您可以在此处查看如何添加日志记录!即使通常 sequelize 已默认激活查询的日志记录!

https://sequelize.org/master/manual/getting-started.html#logging

const sequelize = new Sequelize('sqlite::memory:', {
  // Choose one of the logging options
  logging: console.log,                  // Default, displays the first parameter of the log function call
  logging: (...msg) => console.log(msg), // Displays all log function call parameters
  logging: false,                        // Disables logging
  logging: msg => logger.debug(msg),     // Use custom logger (e.g. Winston or Bunyan), displays the first parameter
  logging: logger.debug.bind(logger)     // Alternative way to use custom logger, displays all messages
});
Run Code Online (Sandbox Code Playgroud)

检查身份验证

如果不记录发生!这可能意味着续集什么都没有,只是在开始时就挂了!测试身份验证以及连接是否正常!

您可以使用身份验证进行测试:

https://sequelize.org/master/manual/getting-started.html#testing-the-connection

try {
  console.log('Gonna authenticate'); // <== to make sure console.log is working and not overrided!
  await sequelize.authenticate();
  console.log('Connection has been established successfully.');
} catch (error) {
  console.error('Unable to connect to the database:', error);
}
Run Code Online (Sandbox Code Playgroud)

如果你没有记录!而Gonna authenticate印刷只是OK!然后该过程挂在authentication 上。哪位提示认证有问题!

检查您的凭据

确保你没有犯任何错误!

检查来自 psql 或其他一些外部客户端的连接

  • 如果它不起作用!它表明 postgres 服务器有问题!或者一些配置!
  • 如果确实有效!那么问题出在nodejs上!还有你的程序!

不要忘记安装 POSTGRES 驱动程序(或您的数据库驱动程序)

根据文档:https : //sequelize.org/master/manual/getting-started.html#installing

 async sync(options) {
    // ...

    // no models defined, just authenticate
    if (!models.length) {
      await this.authenticate(options);
    } else {
      for (const model of models) await model.sync(options);
    }
    if (options.hooks) {
      await this.runHooks('afterBulkSync', options);
    }
    return this;
  }
Run Code Online (Sandbox Code Playgroud)

命令之一!确保你没有忘记这一点!

了解正在发生的事情并更好地调试!(代码源记录)

最好的调试方法!并真正确定问题发生在哪里!是通过向源代码本身添加日志!对我来说,一个快速的方法直接在node_modules. 我在 sequelize repo 上打开了 git!进行了搜索!确定的地方syncauthenticatequery!都住在sequelize.js!你可以在这里查看!可以 CTRL + F 进入方法> authenticate([添加(]。反正!你可以在node_modules! 并开始添加日志!您将知道问题发生在哪个部分!哪位帮你调试问题!

另一种方法是分叉!并使用你的叉子!并且更好地工作!

但是嗯!node_modules 是一种快速的方法!你可以复印一份!也!以确保您不会丢失日志!一旦更新!最后只需卸下整个模块即可清洁!并重新安装!或者只是反转日志创建(撤消)!我发现这是一种有趣的调试方式!

但它应该抛出一个错误

正常应该!通过查看代码源您可以更好地了解!通常应该抛出错误!但是如果一个进程挂了!并且不会抛出任何错误!那么你可以期待这样的结果!这里可能是驱动程序丢失了!还要确保console.log. 工作正常!还有最后一件事!MMM 可能是它nodejs本身的问题(见最后一节)。

我正在使用续集打字稿(不是续集)

非常重要!Sequelize-typescript 只是一个续集包装器!那是为了添加打字稿支持!它提供装饰器和一些功能!也来自续集 v5!续集直接支持打字稿!在这里查看 最新版本的https://sequelize.org/master/manual/typescript.html sequelize-typescript!转而使用 sequelize 的原生声明类型!

作为续集类型脚本包装续集!确保验证 sequelize 文档!

还要注意,有些人在:不要使用装饰器!嗯!嗯!另一个嗯! /sf/answers/4225843261/

续集打字稿

如果您正在使用sequelize,打字稿确认版本sequelize-typescript,并sequelize匹配!根据V5续集的文档!我想V6也应该这样做!而v1对于sequelize,打字稿!

const sequelize = new Sequelize('sqlite::memory:', {
  // Choose one of the logging options
  logging: console.log,                  // Default, displays the first parameter of the log function call
  logging: (...msg) => console.log(msg), // Displays all log function call parameters
  logging: false,                        // Disables logging
  logging: msg => logger.debug(msg),     // Use custom logger (e.g. Winston or Bunyan), displays the first parameter
  logging: logger.debug.bind(logger)     // Alternative way to use custom logger, displays all messages
});
Run Code Online (Sandbox Code Playgroud)

并且不要忘记按照那里的文档需要打字稿的包!
https://www.npmjs.com/package/sequelize-typescript

(您可以在文档本身中检查和验证所有这些信息)

为什么要使用 sequelize-typescript ?

正如已经提到的!Sequelize 对从V5. 按照这里。那么为什么要在它上面使用包装器呢!也使用装饰器!(我不反对装饰者!有些是!根据这里

问问自己为什么?有什么可以续集打字稿的!与本地方式相比的重要优势?如果有明确的事情!请在评论中提及它们!我会更新!这个部分!

如果不!原生可以更好!依赖或多于少!

项目配置

配置!

try {
  console.log('Gonna authenticate'); // <== to make sure console.log is working and not overrided!
  await sequelize.authenticate();
  console.log('Connection has been established successfully.');
} catch (error) {
  console.error('Unable to connect to the database:', error);
}
Run Code Online (Sandbox Code Playgroud)

这是要添加的两个重要内容。

# One of the following:
$ npm install --save pg pg-hstore # Postgres
$ npm install --save mysql2
$ npm install --save mariadb
$ npm install --save sqlite3
$ npm install --save tedious # Microsoft SQL Server
Run Code Online (Sandbox Code Playgroud)

但这不应该是你的问题!否则项目会抛出编译错误!

地狱

Node js 版本(V14 地狱)

是的!这可能是原因!您之前可能已经习惯了它!然后在新的计算机或环境中!它不再起作用了

节点版本可能是问题节点 v15节点 v14!这是一个众所周知的问题!我自己遇到过一次knex.jspostgres (knex.js 是一个查询构建器)!所以你可以看到这是相关的!在我的故事中,代码在我的笔记本电脑和我们部署的旧 vps 上运行良好!但后来我部署在 Windows rdp 上!嗯!繁荣!然后我拉了一段时间的头发!我反映并检查了!没有任何变化!然后我来了嘿!我只更新了nodejs!后来我发现其他人也遇到了同样的事情!简而言之!这一切都开始了nodejs v14(我称之为v14 地狱)!你可以在这里查看我的回答

显然同样的问题总是存在nodejs v15

在这个线程的问题!我们证实了这一点!在我的桌面上一切正常!Nodejs v12!和我朋友的电脑!它没有!nodejs v14nodejs v15。然后我想确认!我安装了nodejs v15和cabo​​om!答对了!执行只是意外停止!没有记录!没有错误!在v12!一切正常!我一开始有错误,然后我纠正了它们!服务器已启动并运行!和续集连接到数据库!

这里的处决

V12 和 v13

我正在显示 v13!v12 也会发生同样的情况!

在此处输入图片说明

npm install sequelize@5 sequelize-typescript@1
Run Code Online (Sandbox Code Playgroud)

酷工作没问题

V14 和 v15 执行

v14

在此处输入图片说明

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es6",
        "moduleResolution": "node",
        "rootDir": "./src",
        "outDir": "./dist",
        "lib": [
            "es2015",
            "es2016",
            "dom"
        ],
        "declaration": true,
        "experimentalDecorators": true,
        "esModuleInterop": true
    },
    "include": [
        "src/**/*"
    ],
    "exclude": [
        "node_modules/**/*",
        "src/**/*.test.tsx",
        "src/**/*.story.tsx",
        "test/**/*"
    ]
}
Run Code Online (Sandbox Code Playgroud)

还有哦!程序意外退出,没有错误输出!

V15

在此处输入图片说明

"experimentalDecorators": true,
"esModuleInterop": true
Run Code Online (Sandbox Code Playgroud)

再次oppsii!程序意外退出,没有错误输出!

v14和之间也没有区别v15!它是V14 HELL

简而言之

V14 HELL是一个已知的和很可能的原因!pg我猜模块有问题!发生了一些变化v14并导致了这个问题!

简而言之!如果没有任何意义!如果您之前使用相同的代码!要做的第一件事!是用 nodejsv13还是v12! 这可以让你远离精神错乱!谁会说nodejs的版本和新的会产生这样的问题!

这是什么问题!nodejs 中的 V14 HELL 是什么?

如果像我一样你想知道细节和发生了什么!?

使用节点 V14!api 发生了一些重大变化!也改变了很多东西!包括Openssl版本!

对于postgres!和pg模块!问题如此线程的评论中所述:

初始的 readyState(一个私有/未记录的 API,用于

pg 使用)的 net.Socket 似乎在 Node 14 中从“关闭”更改为“打开”。

很难用完美的向后兼容性来修复,但我认为我有一个足够接近的补丁。

并根据此公关

您可以在此差异中看到更改

简而言之,如上所述!的行为onReadySate改变了net.Socket!实施的解决方案是根本不使用onReadyState

按照这个

现在,当在其上调用 connect 时,Connection 总是在其流上调用 connect。

检查这一行

在旧版本中,只有当套接字处于开启closed状态时才会调用连接!readyState用法被淘汰!

你能明白!看执行情况!许多事情可能会或不会受到这些核心更改的影响!

相关节点变化

因为我想看看变化发生在哪里!在这里你可以检查

https://github.com/nodejs/node/pull/32272

也可以检查更改日志:

https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V14.md

修复(Postgres v14 地狱)

根据我在这里的回答。

升级pg驱动到>=8.0.3!您只需升级到最新版本即可!

npm install pg@latest --save
Run Code Online (Sandbox Code Playgroud)

你可以检查我们的问题

旧版本在 v7

在此处输入图片说明

更新到 v8

在此处输入图片说明

再次运行 node v15

在此处输入图片说明

塔拉啊啊!而且效果非常好!

如果您不使用postgres! 问题是v14 HELL!意思是你用v13. 它奏效了!然后尝试将您的数据库驱动程序升级到最新版本!

为什么 node v14 + 退出并且没有日志错误

还要提一下突破性的变化!制作pg可在过程退出connect() call。这就是它退出的原因!和日志是可以看到的!更详细的!这是怎么回事!Sequelize 有 postgres 方言实现!哪个用pg!还有PG客户端!建立联系!连接有一个connect事件!当它连接它发射它!并且因为节点 v14 将行为更改为以 open! 开头!流连接被跳过!并且将流视为已连接!哪里不对!并且connect事件是直接发出的!当这种情况发生!客户端将调用连接对象的requestSsl()startup()方法!两者都会调用this._stream.write. 因为流没有连接!发生错误!这个错误不是catch!然后在续集驱动程序中的承诺!将保持悬而未决!然后事件循环变空了!Nodejs 默认行为只是退出!

您可以查看代码行的步骤:

为什么 nodejs 退出(未解决的承诺)

https://github.com/nodejs/node/issues/22088

节点无错误退出且不等待承诺(事件回调)

当 Promise 永远不会解决时会发生什么?

非虚拟机

https://github.com/nvm-sh/nvm

如果你不知道是什么nvm!或者您没有使用nvm. 考虑使用它!因为它是一个非常有趣的工具!Nvm是一个节点版本管理工具

随着 nvm 更改,调试和测试到不同版本的 nodejs!又快又轻!所以并行安装新版本的nodejs!

关于 sequelize.sync() 的注意事项

不要用它production!或者根本没有!(大多数 ORM!和查询构建器(knex.js)使用迁移)。

https://sequelize.org/master/manual/model-basics.html#synchronization-in-production

从文档

如上所示,sync({ force: true }) 和sync({ alter: true }) 可以是破坏性操作。因此,不建议将它们用于生产级软件。相反,应该在Sequelize CLI的帮助下,使用 Migrations的高级概念来完成同步。