Egg: 使用 pg-promise 开发数据库插件,addSingleton 失败

Created on 26 Apr 2018  ·  4Comments  ·  Source: eggjs/egg

  • Node Version: v8.11.1
  • Egg Version: 2.7.1
  • Plugin Name:
  • Plugin Version:
  • Platform: Linux
  • Mini Showcase Repository:


通过修改 egg-mysql 插件,用 pg-promise 库链接 PostgreSQL 数据库,作为新的插件,插件无法被启动,在 addSingleton 时报错,目前查出问题在于 egg-mysql 使用的 ali-rds 模块创建的 client,与 pg-promise 创建的 client 有差异,后者 client 的方法无法被正常代理?

egg-mysql 参考:

'use strict';

const assert = require('assert');
const rds = require('ali-rds');

let count = 0;

module.exports = app => {
  app.addSingleton('mysql', createOneClient);
};

function createOneClient(config, app) {
  assert(config.host && config.port && config.user && config.database,
    `[egg-mysql] 'host: ${config.host}', 'port: ${config.port}', 'user: ${config.user}', 'database: ${config.database}' are required on config`);

  app.coreLogger.info('[egg-mysql] connecting %s@%s:%s/%s',
    config.user, config.host, config.port, config.database);
  const client = rds(config);

  app.beforeStart(function* () {
    const rows = yield client.query('select now() as currentTime;');
    const index = count++;
    app.coreLogger.info(`[egg-mysql] instance[${index}] status OK, rds currentTime: ${rows[0].currentTime}`);
  });
  return client;
}

自己的插件:

'use strict';

const assert = require('assert');
const pgp = require('pg-promise')();

let count = 0;

module.exports = app => {
    app.addSingleton('pp', createOneClient);
};

function createOneClient(config, app) {
    assert(config.host && config.port && config.user && config.database,
        `[egg-pp] 'host: ${config.host}', 'port: ${config.port}', 'user: ${config.user}', 'database: ${config.database}' are required on config`);

    app.coreLogger.info('[egg-pp] connecting %s@%s:%s/%s',
        config.user, config.host, config.port, config.database);

    let client = pgp(config);

    app.beforeStart(async () => {
        const rows = await client.query('select now() as currentTime;');
        const index = count++;
        app.coreLogger.info(`[egg-pp] instance[${index}] status OK, db server currentTime: ${rows[0].currentTime}`);
    });

    // return {c: client};  // 通过 app.pp.c.query(...) 可调用
    return client;          // 无法运行
}

报错:

2018-04-26 18:44:49,824 INFO 1684 [master] node version v8.11.1
2018-04-26 18:44:49,827 INFO 1684 [master] egg version 2.7.1
2018-04-26 18:44:50,785 INFO 1684 [master] agent_worker#1:1690 started (953ms)
/home/work/workspace/ecoio/node_modules/egg/lib/application.js:68
      throw e;
      ^

TypeError: Cannot add property createInstance, object is not extensible
    at Singleton.initSync (/home/work/workspace/ecoio/node_modules/egg/lib/core/singleton.js:35:29)
    at Singleton.init (/home/work/workspace/ecoio/node_modules/egg/lib/core/singleton.js:21:68)
    at Application.addSingleton (/home/work/workspace/ecoio/node_modules/egg/lib/egg.js:396:35)
    at module.exports.app (/home/work/workspace/ecoio/lib/plugin/egg-pp/lib/pg.js:9:9)
    at module.exports.app (/home/work/workspace/ecoio/lib/plugin/egg-pp/app.js:6:28)
    at AppWorkerLoader.loadFile (/home/work/workspace/ecoio/node_modules/egg-core/lib/loader/egg_loader.js:292:30)
    at getLoadUnits.forEach.unit (/home/work/workspace/ecoio/node_modules/egg-core/lib/loader/mixin/custom.js:25:29)
    at Array.forEach (<anonymous>)
    at AppWorkerLoader.loadCustomApp (/home/work/workspace/ecoio/node_modules/egg-core/lib/loader/mixin/custom.js:25:8)
    at AppWorkerLoader.load (/home/work/workspace/ecoio/node_modules/egg/lib/loader/app_worker_loader.js:33:10)
[2018-04-26 18:44:51.735] [cfork:master:1684] worker:1700 disconnect (exitedAfterDisconnect: false, state: disconnected, isDead: false, worker.disableRefork: true)
[2018-04-26 18:44:51.735] [cfork:master:1684] don't fork, because worker:1700 will be kill soon
2018-04-26 18:44:51,736 INFO 1684 [master] app_worker#1:1700 disconnect, suicide: false, state: disconnected, current workers: ["1"]
[2018-04-26 18:44:51.736] [cfork:master:1684] worker:1700 exit (code: 1, exitedAfterDisconnect: false, state: dead, isDead: true, isExpected: false, worker.disableRefork: true)
2018-04-26 18:44:51,739 ERROR 1684 nodejs.AppWorkerDiedError: [master] app_worker#1:1700 died (code: 1, signal: null, suicide: false, state: dead), current workers: []
    at Master.onAppExit (/home/work/workspace/ecoio/node_modules/egg-cluster/lib/master.js:387:21)
    at emitOne (events.js:116:13)
    at Master.emit (events.js:211:7)
    at Messenger.sendToMaster (/home/work/workspace/ecoio/node_modules/egg-cluster/lib/utils/messenger.js:122:17)
    at Messenger.send (/home/work/workspace/ecoio/node_modules/egg-cluster/lib/utils/messenger.js:87:12)
    at EventEmitter.cluster.on (/home/work/workspace/ecoio/node_modules/egg-cluster/lib/master.js:264:22)
    at emitThree (events.js:141:20)
    at EventEmitter.emit (events.js:217:7)
    at ChildProcess.worker.process.once (internal/cluster/master.js:186:13)
    at Object.onceWrapper (events.js:317:30)
name: 'AppWorkerDiedError'

在可用的情况下打印 client

'use strict';

const Controller = require('egg').Controller;

class HomeController extends Controller {
  async index() {

    console.log(this.app.mysql);

    /* 
      RDSClient {
        pool:
        Pool {
          domain: null,
          _events: {},
          _eventsCount: 0,
          _maxListeners: undefined,
          config:
            PoolConfig {
              acquireTimeout: 10000,
              connectionConfig: [Object],
              waitForConnections: true,
              connectionLimit: 5,
              queueLimit: 0 },
          _acquiringConnections: [],
          _allConnections: [ [Object] ],
          _freeConnections: [ [Object] ],
          _connectionQueue: [],
          _closed: false,
          query: [Function],
          getConnection: [Function] },
        createInstance: [Function: bound createInstance],
        createInstanceAsync: [AsyncFunction: bound createInstanceAsync] }
    */

    console.log(this.app.pp.c);

    /* 
      Database {
        connect: [Function],
        query: [Function],
        none: [Function],
        one: [Function],
        many: [Function],
        oneOrNone: [Function],
        manyOrNone: [Function],
        any: [Function],
        result: [Function],
        multiResult: [Function],
        multi: [Function],
        stream: [Function],
        func: [Function],
        proc: [Function],
        map: [Function],
        each: [Function],
        task: [Function],
        taskIf: [Function],
        tx: [Function],
        txIf: [Function] }
    */

    this.ctx.body = 'hello'
  }
}

module.exports = HomeController;

Most helpful comment

你可以先这样 work around,我看看怎么绕过

All 4 comments

目前发现这样也可以解决

function createClient(config, app) {

    // ...

    // return {c: client};  // 通过 app.pp.c.query(...) 可调用
    // return client;          // 无法运行
    return {...client};          // 可正常使用
}

应该是它定义了 preventExtensions 不允许添加新的属性了

你可以先这样 work around,我看看怎么绕过

用 egg-knex 就好了,egg-mysql 没有考虑过除 mysql 以外的客户端

Yiyu He notifications@github.com 于 2018年4月26日周四 下午11:10写道:

你可以先这样 work around,我看看怎么绕过


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/eggjs/egg/issues/2468#issuecomment-384676513, or mute
the thread
https://github.com/notifications/unsubscribe-auth/ABHhMgHdFWvDsIIlvqwORFuknk_Clu2hks5tseNLgaJpZM4Tk8wW
.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

popomore picture popomore  ·  53Comments

fengmk2 picture fengmk2  ·  51Comments

jtyjty99999 picture jtyjty99999  ·  52Comments

atian25 picture atian25  ·  68Comments

fengmk2 picture fengmk2  ·  44Comments