I have a problem deploying a Nodejs app with a Postgresql database. The database comes from Heroku itself (Heroku Postgres add-on, hobby-dev). My app refused to connect to the database.
I found where the problem came from but I can't find a clean solution. And I think I could have misunderstood something (I'm new to Node and Heroku).
Heroku automatically gives me an environment variable DATABASE_CONFIG that includes the port:
postgres://username:password#hostname:port/databasename
Then, to connect with pg in my app, I use process.env.DATABASE_CONFIG as a connection string. I do something like:
const client = new Client({
connectionString: connectionString,
})
client.connect()
This fails to connect.
But if instead of using this environment variable, I cheat and change it, removing the port number from this connection string, it works.
I don't know why but the problem is that Heroku gives you this DATABASE_URL with the port included and you can't change it.
Did I do something wrong? Is there a clean solution to avoid that?
(because what I did is ugly as I hard-coded the DATABASE_CONFIG without the port directly in my code)
Thanks for your help!
First off, I would avoid using new Client() as this can lead to your connection being bottlenecked. Instead, use connection pooling. You can read a more indepth answer into why you want to do that here.
As for you direct issue, personally I have had trouble connecting to heroku postgres databases in the past, but here is a (basic) typical setup that works for me 99% of the time:
let pg = require('pg');
if (process.env.DATABASE_URL) {
pg.defaults.ssl = true;
}
// include an OR statement if you switch between a local dev db and
// a remote heroku environment
let connString = process.env.DATABASE_URL || 'postgresql://postgres:password#localhost:localpostgresport/yourlocaldbname';
const { Pool } = require('pg');
const pool = new Pool({
connectionString : connString
});
My first guess would be that it may have to do with ssl not being enabled. I know that has cause me problems in the past. Secondly, you want to make sure that you uses the process.env.DATABASE_URL, as environment variable should be set as the postgres connection string by Heroku.
Related
When running locally and connecting to Heroku with the same DATABASE_URL, I'm able to connect and query the db perfectly fine.
When the same code is running on Heroku -- the query never returns and will eventually time out.
DB Code:
const connectionString = process.env.DATABASE_URL;
const pool = new Pool(
{
connectionString: connectionString,
ssl: true
}
);
public async query(text: any, params: any): Promise<any> {
return pool.query(text, params);
}
This works as expected when I run on localhost and attach to the Heroku Postgres add-on (Hobby tier), but when deployed to Heroku it no longer works. The DATABASE_URL is loaded correctly though.
Weird one, but if anyone runs into this problem here was our solution:
We used the pg package and were running version ^7.12.1, which allowed us to connect and query the Heroku hosted database locally, but not when the server was deployed on Heroku.
The fix was updating the pg package, which we are now running version ^8.5.1.
I developed a node app server that get data requested through a postgres (sequelize ORM) which send the data to my react nextjs app when requested.
A few days ago I tried to host the application on heroku, which is when all hell broke loose. the application stopped working. I was getting a socket hangup error. I followed the error stack trace until i think i pinpointed the error on when my server request data from my database. I realized there are no more data coming through. Therefore, I am left hanging with a pending promise. I rebuild my backend. I also went back to previous commit when it was working and the application is still not working. The front-end is working bc it is running on a different host but my backend is not receiving data from my db anymore. I have tried everything i can think of and read a bunch of article on stack overflow and Github but have not figure it out yet. Also, I can no longer seed my seed file for some reason (also return pending promise).
ANY HELP WILL BE REALLY APPRECIATED.
I figure out what was the problem. My configuration on the server side with my database was not working. Therefore, I was getting an unresolved promise which caused the application to just keep loading while waiting for the data. By changing my config file to this:
`
const Sequelize = require("sequelize");
let database = process.env.DATABASE_URL;
let sequelize = "";
process.env.DATABASE_URL
? (sequelize = new Sequelize(database))
: (sequelize = new Sequelize(database, "postgres", "", {
dialect: "postgres",
logging: false,
}));
`module.exports = sequelize;
and adding my postgres database manually on my terminal when running heroku pg:psql to see and create my data base. I was able to make the application work once deployed on Heroku.
On Heroku Postgres there is written:
The value of your app’s DATABASE_URL config var might change at any time. You should not rely on this value either inside or outside your Heroku app.
I'm developing a Node.js server that uses node-postgres to connect and manage the connection pool with the database.
But what happens when Heroku changes the DATABASE_URL? How should this problem be managed?
You handle this by always connecting to Postgres using whatever value DATABASE_URL has. For example, you can use this value as a connection string when you create your pool:
const connectionString = process.env.DATABASE_URL
const pool = new Pool({
connectionString: connectionString,
})
Heroku's dynos restart when their environment variables or addons are changed, which should cause your code to pick up the new database connection string when it starts back up.
I am learning NodeJS by building a JWT server. Basically I want to authorize users against credentials in a PostgreSQL database. I am considering node-postgres, passport, pg to connect with PostgreSQL but I have not found anyway to store my connection values encrypted. Ideally I would store them in a properties file so I can change them per environment.
Most examples I see do something like:
var pg = require('pg');
var conString = "postgres://YourUserName:YourPassword#localhost:5432/YourDatabase";
Can someone help show me how to encrypt and use my credentials so I don't have to hard code the plain values in my source?
There seem to exist npm packages for this already. See https://www.npmjs.com/package/secure-conf. Seems to fulfill your needs.
Please note, that you should also secure your Connection to the DB using SSL. See SSL for PostgreSQL connection nodejs for a Solution.
This should help.
if you use sequelize to connect postgres
const sequelize = new Sequelize("DB", usrname, password, {
host: "/var/run/postgresql",
dialect: "postgres",
});
NB: get the host string from your pgsl db might be different //
I struggled today to get my local node.js app to reach out to the db on Heroku instead of settling for a parallel db on my machine. Thanks to a post I tested and then stopped expecting
process.env.DATABASE_URL
to provide the URL and replaced it with the actual URL from
heroku config
along the lines of
var connectionString = "postgres://thinga:thingb#ec2-23-21-119-36.compute-1.amazonaws.com:5432/thingc";.
But that didn't solve the problem completely. I found I also had to use
var pg = require('pg').native;
to force SSL. And in order to get that to work I had to rollback my pg module to
"pg": "2.x"
There must be a better way. Anyone?
P.S. I also set
NODE_ENV: development
but I don't know if that makes any difference.
You helped me fix the same problem on my machine, but I didn't have to go as far as you did.
I had already changed process.env.DATABASE_URL to connectionString after declaring:
var connectionString = 'postgres://thinga:thingb#ec2-54-204-42-119.compute-1.amazonaws.com:thingc';
Adding .native to var pg = require('pg'); seems to have made the difference for me.
I did NOT need to change pg in the dependencies. I left it at "pg": "4.x".
I did not use this: NODE_ENV: development.
But thank you so much for your help.