Использование обещания в поле пароля строки подключения возвращает базу данных, не подключенную

Расшифровка пароля из параметра среды с использованием aws.kms не разрешена для использования в объекте подключения pg-promise. База данных не может подключиться из-за пустого пароля. Пароль определяется примерно через одну секунду с моей локальной машины, спустя много времени после того, как сервер koa готов. Я пробовал все, чтобы заставить GraphQL ждать подключения к базе данных, но я не смог найти много информации о своей проблеме.

При использовании прямого пароля среды все работает по назначению.

Мой db.init.js

const pgp = require("pg-promise")();
const aws = require("aws-sdk");
const kms = new aws.KMS({
    accessKeyId: process.env.ACCESSKEYID,
    secretAccessKey: process.env.SECRETACCESSKEY,
    region: process.env.REGION
});
let params = {
    CiphertextBlob: Buffer.from(
        process.env.ENCRYPTED_DATABASE_PASSWORD,
        "base64"
    )
};
module.exports = kms.decrypt(params, async (err, data) => {
    const password = await data.Plaintext.toString("utf-8");
    const cn = {
        host: process.env.DATABASE_HOST,
        port: process.env.DATABASE_PORT,
        database: process.env.DATABASE_NAME,
        user: process.env.DATABASE_USER,
        password: password,
    };
    return pgp(cn);
});

Работает при изменении db.init.js на

(используя простой пароль вместо зашифрованного пароля):

const pgp = require("pg-promise")();
const cn = {
    host: process.env.DATABASE_HOST,
    port: process.env.DATABASE_PORT,
    database: process.env.DATABASE_NAME,
    user: process.env.DATABASE_USER,
    password: process.env.PLAIN_DATABASE_PASSWORD
};
module.exports = pgp(cn);

Использование его в схеме:

const { GraphQLSchema, GraphQLObjectType, GraphQLString} = require("graphql");
const db = require("./db.init")
const schema = new GraphQLSchema({
    query: new GraphQLObjectType({
        name: "RootQueryType",
        fields: () => ({
            sql: {
                type: GraphQLString,
                async resolve() {
                    return await db
                        .any("SELECT * FROM user;")
                        .then(data => data[0].name)
                        .catch(err => `Something went wrong: ${err}`);
                }
            }
        })
    })
});
module.exports = schema;

Файл сервера

const Koa = require('koa');
const mount = require('koa-mount');
const graphqlHTTP = require('koa-graphql');
const schema = require('./schemas');
function createServer() {
    server.use(
        mount(
            '/graphql',
            graphqlHTTP({
                schema,
                graphiql: true,
            })
        )
    );
    return server;
}

Локальный сервер

const server = require("./server");
const port = 4000;
server().listen(port, err => {
    if (err) throw err;
    console.log(`> Ready on http://localhost:${port}/graphql`);
});

Лямбда-функция

const awsServerlessKoa = require('aws-serverless-koa');
const serverlessMiddleware = require('aws-serverless-koa/middleware');
const server = require('./server');
server().use(serverlessMiddleware());
module.exports.handler = awsServerlessKoa(server);

GraphQL выдает ошибку: «db.any не является функцией». В объекте db в schema.js все еще находится неразрешенный объект aws kms в соединении. Я не пробовал это как лямбда-функцию, потому что я должен убедиться, что база данных готова, когда функция срабатывает.


person Florat    schedule 17.09.2019    source источник
comment
Как вы ожидаете, что это сработает, если в первом примере вы не экспортируете объект db, а функцию, которая его возвращает. И затем вы импортируете его, как если бы он напрямую экспортировал объект базы данных. Ошибка о том, что метод any не существует в возвращаемой функции, кажется очевидным результатом.   -  person vitaly-t    schedule 17.09.2019


Ответы (1)


Спасибо, vitaly-t, за комментарий, наконец-то разобрался:

db.init.js

const pgp = require('pg-promise')();
const aws = require('aws-sdk');
const kms = new aws.KMS({
  accessKeyId: process.env.ACCESSKEYID,
  secretAccessKey: process.env.SECRETACCESSKEY,
  region: process.env.REGION,
});
const params = {
  CiphertextBlob: Buffer.from(
    process.env.DATABASE_PASSWORD,
    'base64',
  ),
};
async function getDb() {
  return kms
    .decrypt(params)
    .promise()
    .then(async res => {
      const password = await res.Plaintext.toString('utf-8');
      return pgp({
        host: process.env.DATABASE_HOST,
        port: process.env.DATABASE_PORT,
        database: process.env.DATABASE_NAME,
        user: process.env.DATABASE_USER,
        password,
      });
    });
}
module.exports = getDb();

схема.js

const { importSchema } = require('graphql-import');
const { makeExecutableSchema } = require('graphql-tools');
const dbp = require('../db/init');
const schema = importSchema('src/api/schemas.graphql');
module.exports = dbp.then(db => {
  const resolvers = {
    Query: {
      user: () => {
        return db
          .any('SELECT * FROM user;')
          .then(data => data[0].name);
      },
    },
  };
  return makeExecutableSchema({
    typeDefs: schema,
    resolvers,
  });
});

схемы.graphql

type Query { user: String } schema { query: Query }

сервер.js

const Koa = require('koa');
const mount = require('koa-mount');
const graphqlHTTP = require('koa-graphql');
const schema = require('../api/schemas');
function createServer() {
  const server = new Koa();
  server.use(
    mount(
      '/graphql',
      graphqlHTTP(async () => ({
        schema: await schema,
        graphiql: true,
      })),
    ),
  );
  return server;
}
module.exports = createServer;

server.local.js

const server = require('./server');
const port = 4000;
server().listen(port, err => {
  if (err) throw err;
  console.log(`> Ready on http://localhost:${port}/graphql`);
});

Только лямбда-функцию я не тестировал. Должно быть прямо.

person Florat    schedule 17.09.2019