Search code examples
mysqlnode.jsgoogle-app-enginesequelize.jsgoogle-cloud-sql

Google App Engine with Cloud SQL Deploy Error Using Sequelize


I want to deploy my node app to app engine and use cloud sql mysql with Sequelize for the ORM, however i get the below error on deployment, with no further info to debug.

my yaml is (with redacted details):

env: flex
runtime: nodejs
env_variables:
  SQL_USER: -
  SQL_PASSWORD: -
  SQL_DATABASE: -
  INSTANCE_CONNECTION_NAME: -

  beta_settings:
  cloud_sql_instances: -

Unable to connect to SQL database: undefined Uncaught Error { filename: '/app/node_modules/sequelize/lib/dialects/mysql/connection-manager.js', line: 133, row: 19, message: 'connect ENOENT /cloudsql/app:europe-west1:db', type: 'SequelizeConnectionError', stack: 'SequelizeConnectionError: connect ENOENT /cloudsql/app:europe-west1:db\n at Promise.tap.then.catch.err (/app/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:133:19)\n at tryCatcher (/app/node_modules/bluebird/js/release/util.js:16:23)\n at Promise._settlePromiseFromHandler (/app/node_modules/bluebird/js/release/promise.js:512:31)\n at Promise._settlePromise (/app/node_modules/bluebird/js/release/promise.js:569:18)\n at Promise._settlePromise0 (/app/node_modules/bluebird/js/release/promise.js:614:10)\n at Promise._settlePromises (/app/node_modules/bluebird/js/release/promise.js:690:18)\n at _drainQueueStep (/app/node_modules/bluebird/js/release/async.js:138:12)\n at _drainQueue (/app/node_modules/bluebird/js/release/async.js:131:9)\n at Async._drainQueues (/app/node_modules/bluebird/js/release/async.js:147:5)\n at Immediate.Async.drainQueues [as _onImmediate] (/app/node_modules/bluebird/js/release/async.js:17:14)\n at runCallback (timers.js:705:18)\n at tryOnImmediate (timers.js:676:5)\n at processImmediate (timers.js:658:5)', arguments: undefined }

The ORM code:

const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASS, {
      dialect: 'mysql',
      host: '/cloudsql/app:europe-west1:db',
      pool: {
          max: 5,
          min: 0,
          acquire: 30000,
          idle: 10000
      },
      dialectOptions: {
          socketPath: '/cloudsql/app:europe-west1:db'
      },
      logging: false
    });

Solution

  • First, your app.yaml shouldn't have beta_settings: indented:

    ...
      INSTANCE_CONNECTION_NAME: <YOUR_INSTANCE_CONNECTION_NAME>
    
    beta_settings:
      cloud_sql_instances: <YOUR_INSTANCE_CONNECTION_NAME>
    

    Next, the unix socket is at /cloudsql/<YOUR_INSTANCE_CONNECTION_NAME>. You should use the environment variable you specified in your app.yaml to set this programmatically:

    socketPath: util.format('/cloudsql/%s', process.env.INSTANCE_CONNECTION_NAME), // '/cloudsql/<YOUR_INSTANCE_CONNECTION_NAME>`
    

    You also specify SQL_USER, SQL_PASSWORD, SQL_DATABASE as env vars in your app.yaml, but call process.env.DB_USER, process.env.DB_PASS, process.env.DB_NAME. They need to be consistent if you want them to have any values.

    Finally, Sequelize is somewhat unclear on how best to use a unix socket - host and dialectOptions.socketPath probably shouldn't both be set. Judging from the Sequelize docs, I would suggest just using socketPath:

    const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASS, {
          dialect: 'mysql',
          pool: {
              max: 5,
              min: 0,
              acquire: 30000,
              idle: 10000
          },
          dialectOptions: {
              socketPath: util.format('/cloudsql/%s', process.env.INSTANCE_CONNECTION_NAME),
          },
          logging: false
        });