Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#3340 Connection settings can be an async function only for PG client #3364

Closed
wants to merge 1 commit into from
Closed

#3340 Connection settings can be an async function only for PG client #3364

wants to merge 1 commit into from

Conversation

Ali-Dalal
Copy link

No description provided.

return new Bluebird(function(resolver, rejecter) {
return new Bluebird(async function(resolver, rejecter) {
if (typeof client.connectionSettings === 'function')
client.connectionSettings = await client.connectionSettings();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to resolve settings on every acquisition? Why not store them after lazy loading originally?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kibertoad pls correct me if I am wrong. To my understanding, Node runtime will execute this function only one time and store the result in memory.
Is this what you asking for?

let tmpSettings;
if (typeof client.connectionSettings === 'function')
  if(! tmpSettings)
        tmpSettings = await client.connectionSettings();
  client.connectionSettings = tmpSettings;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ali-Dalal node runtime will not automatically store anything to memory. Each call to client.connectionSettings() creates new promise that gets executed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@elhigu What about the above snippet?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe connection settings should not be set before this point... is there any reason why they would need to be cloned already in client.js?

Copy link
Author

@Ali-Dalal Ali-Dalal Jul 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried some examples and if you can have a look at the following output

The code:

//dialects/pg/index.js
  acquireRawConnection() {
    const client = this;
    return new Bluebird(async function(resolver, rejecter) {
      console.log("Executing function");
      if (typeof client.connectionSettings === 'function') {
        client.connectionSettings = await client.connectionSettings();
      }
//... rest of the code

//knexfile.js
//...settings
    production: {
        client: 'pg',
        connection: async function () {
            console.log("executing function in connection");
            if (!dbConfig) {
                let secret = await getSecretFromSecretManager(`KEY_NAME`);
                let connection = JSON.parse(secret.SecretString);
                dbConfig = {
                    host: connection.host,
                    user: connection.username,
                    password: connection.password,
                    database: connection.db_name
                };
            }
            return dbConfig;
        },
//...rest of settings

log:
for the first time:

Executing function
executing function in connection
getting secret from secret manager
  knex:client acquired connection from pool: __knexUid1 +0ms
  knex:query select **** undefined +0ms
  knex:bindings [ 'name', 1 ] undefined +0ms
  knex:client releasing connection to pool: __knexUid1 +403ms

for the 2nd time:

Executing function
  knex:client acquired connection from pool: __knexUid2 +2m
  knex:query select ***undefined +2m
  knex:bindings [ 'name', 1 ] undefined +2m
  knex:client releasing connection to pool: __knexUid2 +408ms

From the output above, the production connection config function is executed only 1 time and this mean fetching the db config from secret manager or any other provider will be called only 1 time.

To answer your question,

maybe connection settings should not be set before this point... is there any reason why they would need to be cloned already in client.js?

the reason is if we switch cleint.js to export an async function then every module that needs to use client.js has to require it like this.

require('client').then(function(){
//...rest of the code
})

This is not freidnly code :(

can you please give a resolution on the output above and tell me your thoughts?

I tried the code of this pull request on staging environment and it works like a charm.

I've seen around 6 people asking for this feature.

If you are ok wtih it then I can write integration test and setup the rest of dialects

Thanks.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@elhigu What about the above snippet?

That doesn't work either, because you are creating new tmsSettings on every call to aquireRawConnection.

tmpSettings should be defined outside the scope

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe connection settings should not be set before this point... is there any reason why they would need to be cloned already in client.js?

I meant with that to use directly config.connection from acquireRawConnection, but I suppose it is not exposed or something. This was just something that really looks horrible:

client.connectionSettings = await client.connectionSettings();

So to prevent that + moving resolving real configuration to base implementation should be done by adding new async function to base client, which resolves configuration and which can be shared between every dialect.

Actually I don't thing there should be anything dialect specific in this feature (except for calling some base implementation function to get the config).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@elhigu Thanks for the information.

So to prevent that + moving resolving real configuration to base implementation should be done by adding new async function to base client, which resolves configuration and which can be shared between every dialect.

Can you guide me more?

//client.js
function Client(config = {}) {
  this.config = config;
// How to resolve config.connectionSettings if it is async function?
  this.logger = new Logger(config);
//...rest of client code
module.exports = Client;

for example, if the client is a sync function and we need to convert it to an async function then everytime we need to use the client, we have to require in the following style

require('client').then(()=>{})

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By adding a new async method to the Client class. The same way that other methods of that class are implemented. https://github.com/tgriesser/knex/pull/3364/files#diff-50cfa59973c04321b5da0c6da0fdf4feL73

Copy link
Collaborator

@kibertoad kibertoad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs integration test

@elhigu
Copy link
Member

elhigu commented Jul 26, 2019

This relates to issue #3340

@kibertoad
Copy link
Collaborator

@Ali-Dalal Any updates?

@Ali-Dalal
Copy link
Author

@kibertoad I haven't gotten the chance to modify the PR yet. for now, I am using Knex from my account's repo which I completely don't agree with.

I will try to modify the PR tomorrow and ask for the feed back again

@Ali-Dalal
Copy link
Author

closing this PR as it is a duplication of #3403
#3403

@Ali-Dalal Ali-Dalal closed this Aug 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants