firebase / firebase-tools

The Firebase Command Line Tools
MIT License
4.02k stars 938 forks source link

Functions with the Cloud SQL Node Connector have performance penalty (500–930 ms) for each function unless lazy init a global pool and connector #6894

Closed fuelkoy closed 7 months ago

fuelkoy commented 7 months ago

[REQUIRED] Environment info

firebase-tools: 13.5.1

Platform:

Host Name:                 DESKTOP-6BMEHR6
OS Name:                   Microsoft Windows 11 Pro
OS Version:                10.0.22621 N/A Build 22621
OS Manufacturer:           Microsoft Corporation
OS Configuration:          Standalone Workstation
OS Build Type:             Multiprocessor Free
Registered Owner:          Kehitys
Registered Organization:   N/A
Product ID:                00330-52779-93116-AAOEM
Original Install Date:     17.10.2023, 9.52.34
System Boot Time:          15.2.2024, 8.09.01
System Manufacturer:       Dell Inc.
System Model:              Latitude 5500
System Type:               x64-based PC

[REQUIRED] Test case

https://github.com/fuelkoy/nodeJsSqlConnector

[REQUIRED] Steps to reproduce

  1. firebase login
  2. firebase init functions, choose typescript, remove npm run lint from firebase.json predeploy
  3. Set the project ready to use esm with esbuild as it seems to be the only viable solution to use esm in firebase functions (based on the following: https://github.com/firebase/firebase-tools/issues/2994#issuecomment-1062998994 and https://stackoverflow.com/questions/73953672/problem-deploying-firebase-function-with-typescript-using-es-module-system)
  4. type to "module" in package.json, and add the following scripts
    "dev:tsc": "tsc --watch --preserveWatchOutput",
    "dev:node": "firebase emulators:start --only functions",
    "dev:esbuild": "pnpm run build --watch",
    "dev": "run-p dev:*",
    "build": "esbuild src/index.ts --bundle --platform=node --outfile=lib/index.js --format=esm --external:./node_modules/*",
  5. Set the following in tsconfig.json to be able to use ESM with minimal errors

    {
    // Esbuild with Firebase functions
    // https://www.totaltypescript.com/build-a-node-app-with-typescript-and-esbuild
    "compilerOptions": {
    "jsx": "react",
    "allowJs": true,
    "esModuleInterop": true,
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "moduleDetection": "force",
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "noEmit": true,
    "noUncheckedIndexedAccess": true,
    "resolveJsonModule": true,
    "strict": true,
    "strictNullChecks": true,
    "lib": [
      "ES2022"
    ],
    "target": "ES2022",
    "skipLibCheck": true,
    "useUnknownInCatchVariables": true,
    
    },
    "include": [
    "src",
    ]
    }
  6. Install packages, pnpm i @google-cloud/cloud-sql-connector @google-cloud/functions-framework (I'm using pnpm) dotenv google-auth-library mysql2 esbuild npm-run-all
  7. Set environment variables
  8. npm run deploy

[REQUIRED] Expected behavior

Firebase functions should pick up GOOGLE_APPLICATION_CREDENTIALS even for cases it is needed outside the functions (like the case for the Cloud SQL Node Connector)

Firebase should populate ADC automatically (as when starting the emulator) or pick it up if gcloud init and gcloud auth application-default login are called. GOOGLE_APPLICATION_CREDENTIALS points to C:\Users\MyUser\AppData\Roaming\firebase\ownerEmail_application_default_credentials.json which is created automatically when starting the emulator. But when developing locally trying to use ADC from gcloud auth application-default login or deploying GOOGLE_APPLICATION_CREDENTIALS is empty and initializing the connector and the pool on global scope will fail with the following error: Error: Could not load the default credentials. Cloud SQL Node Connector documentation shows that the connector and pool are made globally: https://github.com/GoogleCloudPlatform/cloud-sql-nodejs-connector?tab=readme-ov-file#using-with-mysql

It is possible to workaround this by making a initializeConnection function that will then be called inside each funtion where pool and connector are gotten and then used. BUT this will introduce a hefty 500–930 ms connection initialization penalty to each function start

Firebase Functions should pick up ADC also when deploying from

  1. The default ADC source it uses C:\Users\MyUser\AppData\Roaming\firebase\ownerEmail_application_default_credentials.json
  2. Or at least from the default ADC source: Linux, macOS: $HOME/.config/gcloud/application_default_credentials.json Windows: %APPDATA%\gcloud\application_default_credentials.json https://cloud.google.com/docs/authentication/application-default-credentials#personal
  3. Or set environment variable through console
    export GOOGLE_APPLICATION_CREDENTIALS="KEY_PATH"
    $env:GOOGLE_APPLICATION_CREDENTIALS="KEY_PATH"
  4. Or set environment variable through console cross-env (for example)

I had a long discussion with the Cloud SQL Node Connector team about this (found in here: https://github.com/GoogleCloudPlatform/cloud-sql-nodejs-connector/issues/312#issuecomment-2008879612) and it points out to the problem of setting the GOOGLE_APPLICATION_CREDENTIALS in Firebase Functions (windows specifically). The problem seems to relate to this comment:

.env variables are only accessible from inside the function! (not outside, meaning inside onRequest( request, response) => {...} ). That's it.

As the document says, "Once your custom environment variables are deployed, your function code can access them."

https://github.com/firebase/firebase-tools/issues/6499#issuecomment-1824982590

If this is the case and Firebase Functions will not pick up GOOGLE_APPLICATION_CREDENTIALS in global scope Firebase Functions with the Cloud SQL with the Cloud SQL Node Connector (which Google itself recommends to use over Cloud SQL Auth proxy https://cloud.google.com/blog/products/databases/cloud-sql-nodejs-connector-is-ga) are non-usable due to the non-accepted performance penalty.

[REQUIRED] Actual behavior

Run to use gcloud auth application-default login ADC: $env:GOOGLE_APPLICATION_CREDENTIALS="C:\Users\Kehitys\AppData\Roaming\gcloud\application_default_credentials.json"

pnpm dev (build and start emulator):

[debug] [2024-03-20T07:48:50.170Z] ----------------------------------------------------------------------
[debug] [2024-03-20T07:48:50.173Z] Command:       C:\Program Files\nodejs\node.exe C:\Users\Kehitys\AppData\Local\pnpm\global\5\node_modules\firebase-tools\lib\bin\firebase.js emulators:start --only functions --debug
[debug] [2024-03-20T07:48:50.173Z] CLI Version:   13.5.1
[debug] [2024-03-20T07:48:50.174Z] Platform:      win32
[debug] [2024-03-20T07:48:50.174Z] Node Version:  v20.10.0
[debug] [2024-03-20T07:48:50.174Z] Time:          Wed Mar 20 2024 09:48:50 GMT+0200 (Itä-Euroopan normaaliaika)
[debug] [2024-03-20T07:48:50.174Z] ----------------------------------------------------------------------
[debug] 
[debug] [2024-03-20T07:48:50.337Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
[debug] [2024-03-20T07:48:50.339Z] > authorizing via signed-in user (kehitys@world.fuelk.com)
[info] i  emulators: Starting emulators: functions {"metadata":{"emulator":{"name":"hub"},"message":"Starting emulators: functions"}}
[debug] [2024-03-20T07:48:50.350Z] [logging] Logging Emulator only supports listening on one address (127.0.0.1). Not listening on ::1
[debug] [2024-03-20T07:48:50.351Z] assigned listening specs for emulators {"user":{"hub":[{"address":"127.0.0.1","family":"IPv4","port":4400},{"address":"::1","family":"IPv6","port":4400}],"ui":[{"address":"127.0.0.1","family":"IPv4","port":4000},{"address":"::1","family":"IPv6","port":4000}],"logging":[{"address":"127.0.0.1","family":"IPv4","port":4500}]},"metadata":{"message":"assigned listening specs for emulators"}}
[debug] [2024-03-20T07:48:50.389Z] [hub] writing locator at C:\Users\Kehitys\AppData\Local\Temp\hub-fuelkdev.json
[debug] [2024-03-20T07:48:50.413Z] [functions] Functions Emulator only supports listening on one address (127.0.0.1). Not listening on ::1
[debug] [2024-03-20T07:48:50.414Z] [eventarc] Eventarc Emulator only supports listening on one address (127.0.0.1). Not listening on ::1
[debug] [2024-03-20T07:48:50.414Z] late-assigned ports for functions and eventarc emulators {"user":{"hub":[{"address":"127.0.0.1","family":"IPv4","port":4400},{"address":"::1","family":"IPv6","port":4400}],"ui":[{"address":"127.0.0.1","family":"IPv4","port":4000},{"address":"::1","family":"IPv6","port":4000}],"logging":[{"address":"127.0.0.1","family":"IPv4","port":4500}],"functions":[{"address":"127.0.0.1","family":"IPv4","port":5001}],"eventarc":[{"address":"127.0.0.1","family":"IPv4","port":9299}]},"metadata":{"message":"late-assigned ports for functions and eventarc emulators"}}
[warn] !  functions: The following emulators are not running, calls to these services from the Functions emulator will affect production: auth, firestore, database, hosting, pubsub, storage {"metadata":{"emulator":{"name":"functions"},"message":"The following emulators are not running, calls to these services from the Functions emulator will affect production: \u001b[1mauth, firestore, database, hosting, pubsub, storage\u001b[22m"}}
[warn] !  functions: Your GOOGLE_APPLICATION_CREDENTIALS environment variable points to C:\Users\Kehitys\AppData\Roaming\gcloud\application_default_credentials.json. Non-emulated services will access production using these credentials. Be careful! {"metadata":{"emulator":{"name":"functions"},"message":"Your GOOGLE_APPLICATION_CREDENTIALS environment variable points to C:\\Users\\Kehitys\\AppData\\Roaming\\gcloud\\application_default_credentials.json. Non-emulated services will access production using these credentials. Be careful!"}}
[debug] [2024-03-20T07:48:50.421Z] > refreshing access token with scopes: []
[debug] [2024-03-20T07:48:50.423Z] >>> [apiv2][query] POST https://www.googleapis.com/oauth2/v3/token [none]
[debug] [2024-03-20T07:48:50.425Z] >>> [apiv2][body] POST https://www.googleapis.com/oauth2/v3/token [omitted]
[debug] [2024-03-20T07:48:50.501Z] <<< [apiv2][status] POST https://www.googleapis.com/oauth2/v3/token 200
[debug] [2024-03-20T07:48:50.501Z] <<< [apiv2][body] POST https://www.googleapis.com/oauth2/v3/token [omitted]
[debug] [2024-03-20T07:48:50.529Z] >>> [apiv2][query] GET https://firebase.googleapis.com/v1beta1/projects/fuelkdev/adminSdkConfig [none]
[debug] [2024-03-20T07:48:51.046Z] <<< [apiv2][status] GET https://firebase.googleapis.com/v1beta1/projects/fuelkdev/adminSdkConfig 200
[debug] [2024-03-20T07:48:51.046Z] <<< [apiv2][body] GET https://firebase.googleapis.com/v1beta1/projects/fuelkdev/adminSdkConfig {"projectId":"fuelkdev","storageBucket":"fuelkdev.appspot.com","locationId":"europe-west"}
[debug] [2024-03-20T07:48:51.069Z] Ignoring unsupported arg: auto_download {"metadata":{"emulator":{"name":"ui"},"message":"Ignoring unsupported arg: auto_download"}}
[debug] [2024-03-20T07:48:51.070Z] Ignoring unsupported arg: port {"metadata":{"emulator":{"name":"ui"},"message":"Ignoring unsupported arg: port"}}
[debug] [2024-03-20T07:48:51.070Z] Starting Emulator UI with command {"binary":"node","args":["C:\\Users\\Kehitys\\.cache\\firebase\\emulators\\ui-v1.11.8\\server\\server.mjs"],"optionalArgs":[],"joinArgs":false} {"metadata":{"emulator":{"name":"ui"},"message":"Starting Emulator UI with command {\"binary\":\"node\",\"args\":[\"C:\\\\Users\\\\Kehitys\\\\.cache\\\\firebase\\\\emulators\\\\ui-v1.11.8\\\\server\\\\server.mjs\"],\"optionalArgs\":[],\"joinArgs\":false}"}}
[info] i  ui: Emulator UI logging to ui-debug.log {"metadata":{"emulator":{"name":"ui"},"message":"Emulator UI logging to \u001b[1mui-debug.log\u001b[22m"}}
[debug] [2024-03-20T07:48:51.438Z] Web / API server started at 127.0.0.1:4000
 {"metadata":{"emulator":{"name":"ui"},"message":"Web / API server started at 127.0.0.1:4000\n"}}
[debug] [2024-03-20T07:48:51.439Z] Web / API server started at ::1:4000
 {"metadata":{"emulator":{"name":"ui"},"message":"Web / API server started at ::1:4000\n"}}
[info] i  functions: Watching "C:\Users\Kehitys\Documents\GitHub\nodeJsSqlConnector\functions" for Cloud Functions... {"metadata":{"emulator":{"name":"functions"},"message":"Watching \"C:\\Users\\Kehitys\\Documents\\GitHub\\nodeJsSqlConnector\\functions\" for Cloud Functions..."}}
[debug] [2024-03-20T07:48:51.628Z] Validating nodejs source
[warn] !  functions: package.json indicates an outdated version of firebase-functions. Please upgrade using npm install --save firebase-functions@latest in your functions directory. 
[debug] [2024-03-20T07:48:53.671Z] > [functions] package.json contents: {
  "name": "functions",
  "scripts": {
    "dev:tsc": "tsc --watch --preserveWatchOutput",
    "dev:node": "firebase emulators:start --only functions --debug",
    "dev:esbuild": "pnpm run build --watch",
    "dev": "run-p dev:*",
    "build": "esbuild src/index.ts --bundle --platform=node --outfile=lib/index.js --format=esm --external:./node_modules/*",
    "serve": "firebase emulators:start --only functions",
    "shell": "npm run build && firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "engines": {
    "node": "20"
  },
  "type": "module",
  "main": "lib/index.js",
  "dependencies": {
    "@google-cloud/cloud-sql-connector": "^1.2.4",
    "@google-cloud/functions-framework": "^3.3.0",
    "dotenv": "^16.4.5",
    "firebase-admin": "^12.0.0",
    "firebase-functions": "^4.8.0",
    "google-auth-library": "^9.7.0",
    "mysql2": "^3.9.2"
  },
  "devDependencies": {
    "@types/node": "^20.11.30",
    "@typescript-eslint/eslint-plugin": "^7.3.1",
    "@typescript-eslint/parser": "^7.3.1",
    "cross-env": "^7.0.3",
    "esbuild": "^0.20.2",
    "eslint": "^8.9.0",
    "eslint-config-google": "^0.14.0",
    "eslint-plugin-import": "^2.25.4",
    "firebase-functions-test": "^3.1.0",
    "npm-run-all": "^4.1.5",
    "typescript": "^5.4.2"
  },
  "private": true
}
[debug] [2024-03-20T07:48:53.674Z] Building nodejs source
[debug] [2024-03-20T07:48:53.675Z] Failed to find version of module node: reached end of search path C:\Users\Kehitys\Documents\GitHub\nodeJsSqlConnector\functions\node_modules
[info] +  functions: Using node@20 from host. 
[info] i  functions: Loaded environment variables from .env. 
[debug] [2024-03-20T07:48:53.685Z] Could not find functions.yaml. Must use http discovery
[debug] [2024-03-20T07:48:53.703Z] Found firebase-functions binary at 'C:\Users\Kehitys\Documents\GitHub\nodeJsSqlConnector\functions\node_modules\.bin\firebase-functions'
[info] Serving at port 8540

[info] undefined

[error] Error: Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information.
    at GoogleAuth.getApplicationDefaultAsync (C:\Users\Kehitys\Documents\GitHub\nodeJsSqlConnector\functions\node_modules\.pnpm\google-auth-library@9.7.0\node_modules\google-auth-library\build\src\auth\googleauth.js:271:15)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async GoogleAuth.getClient (C:\Users\Kehitys\Documents\GitHub\nodeJsSqlConnector\functions\node_modules\.pnpm\google-auth-library@9.7.0\node_modules\google-auth-library\build\src\auth\googleauth.js:695:17)
    at async GoogleAuth.request (C:\Users\Kehitys\Documents\GitHub\nodeJsSqlConnector\functions\node_modules\.pnpm\google-auth-library@9.7.0\node_modules\google-auth-library\build\src\auth\googleauth.js:748:24)
    at async SQLAdminFetcher.getInstanceMetadata (file:///C:/Users/Kehitys/Documents/GitHub/nodeJsSqlConnector/functions/node_modules/.pnpm/@google-cloud+cloud-sql-connector@1.2.4/node_modules/@google-cloud/cloud-sql-connector/dist/mjs/sqladmin-fetcher.js:88:21)
    at async CloudSQLInstance.performRefresh (file:///C:/Users/Kehitys/Documents/GitHub/nodeJsSqlConnector/functions/node_modules/.pnpm/@google-cloud+cloud-sql-connector@1.2.4/node_modules/@google-cloud/cloud-sql-connector/dist/mjs/cloud-sql-instance.js:117:26)
    at async CloudSQLInstance.getCloudSQLInstance (file:///C:/Users/Kehitys/Documents/GitHub/nodeJsSqlConnector/functions/node_modules/.pnpm/@google-cloud+cloud-sql-connector@1.2.4/node_modules/@google-cloud/cloud-sql-connector/dist/mjs/cloud-sql-instance.js:21:9)
    at async CloudSQLInstanceMap.loadInstance (file:///C:/Users/Kehitys/Documents/GitHub/nodeJsSqlConnector/functions/node_modules/.pnpm/@google-cloud+cloud-sql-connector@1.2.4/node_modules/@google-cloud/cloud-sql-connector/dist/mjs/connector.js:46:36)
    at async Connector.getOptions (file:///C:/Users/Kehitys/Documents/GitHub/nodeJsSqlConnector/functions/node_modules/.pnpm/@google-cloud+cloud-sql-connector@1.2.4/node_modules/@google-cloud/cloud-sql-connector/dist/mjs/connector.js:106:9)
    at async file:///C:/Users/Kehitys/Documents/GitHub/nodeJsSqlConnector/functions/lib/index.js:17:18

[debug] [2024-03-20T07:49:00.630Z] Got response code 400; body Failed to generate manifest from function source: Error: Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information.
[error] !!  functions: Failed to load function definition from source: FirebaseError: Functions codebase could not be analyzed successfully. It may have a syntax or runtime error {"metadata":{"emulator":{"name":"functions"},"message":"Failed to load function definition from source: FirebaseError: Functions codebase could not be analyzed successfully. It may have a syntax or runtime error"}}
[info] 
┌─────────────────────────────────────────────────────────────┐
│ ✔  All emulators ready! It is now safe to connect your app. │
│ i  View Emulator UI at http://127.0.0.1:4000/               │
└─────────────────────────────────────────────────────────────┘

┌───────────┬────────────────┬─────────────────────────────────┐
│ Emulator  │ Host:Port      │ View in Emulator UI             │
├───────────┼────────────────┼─────────────────────────────────┤
│ Functions │ 127.0.0.1:5001 │ http://127.0.0.1:4000/functions │
└───────────┴────────────────┴─────────────────────────────────┘
  Emulator Hub running at 127.0.0.1:4400
  Other reserved ports: 4500

Issues? Report them at https://github.com/firebase/firebase-tools/issues and attach the *-debug.log files.

pnpm deploy:

[debug] [2024-03-20T07:52:48.001Z] ----------------------------------------------------------------------
[debug] [2024-03-20T07:52:48.005Z] Command:       C:\Program Files\nodejs\node.exe C:\Users\Kehitys\AppData\Local\pnpm\global\5\node_modules\firebase-tools\lib\bin\firebase.js deploy --only functions --debug
[debug] [2024-03-20T07:52:48.005Z] CLI Version:   13.5.1
[debug] [2024-03-20T07:52:48.005Z] Platform:      win32
[debug] [2024-03-20T07:52:48.005Z] Node Version:  v20.10.0
[debug] [2024-03-20T07:52:48.005Z] Time:          Wed Mar 20 2024 09:52:48 GMT+0200 (Itä-Euroopan normaaliaika)
[debug] [2024-03-20T07:52:48.006Z] ----------------------------------------------------------------------
[debug] 
[debug] [2024-03-20T07:52:48.086Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
[debug] [2024-03-20T07:52:48.088Z] > authorizing via signed-in user (kehitys@world.fuelk.com)
[debug] [2024-03-20T07:52:48.089Z] [iam] checking project fuelkdev for permissions ["cloudfunctions.functions.create","cloudfunctions.functions.delete","cloudfunctions.functions.get","cloudfunctions.functions.list","cloudfunctions.functions.update","cloudfunctions.operations.get","firebase.projects.get"]
[debug] [2024-03-20T07:52:48.092Z] >>> [apiv2][query] POST https://cloudresourcemanager.googleapis.com/v1/projects/fuelkdev:testIamPermissions [none]
[debug] [2024-03-20T07:52:48.092Z] >>> [apiv2][(partial)header] POST https://cloudresourcemanager.googleapis.com/v1/projects/fuelkdev:testIamPermissions x-goog-quota-user=projects/fuelkdev
[debug] [2024-03-20T07:52:48.093Z] >>> [apiv2][body] POST https://cloudresourcemanager.googleapis.com/v1/projects/fuelkdev:testIamPermissions {"permissions":["cloudfunctions.functions.create","cloudfunctions.functions.delete","cloudfunctions.functions.get","cloudfunctions.functions.list","cloudfunctions.functions.update","cloudfunctions.operations.get","firebase.projects.get"]}
[debug] [2024-03-20T07:52:48.363Z] <<< [apiv2][status] POST https://cloudresourcemanager.googleapis.com/v1/projects/fuelkdev:testIamPermissions 200
[debug] [2024-03-20T07:52:48.364Z] <<< [apiv2][body] POST https://cloudresourcemanager.googleapis.com/v1/projects/fuelkdev:testIamPermissions {"permissions":["cloudfunctions.functions.create","cloudfunctions.functions.delete","cloudfunctions.functions.get","cloudfunctions.functions.list","cloudfunctions.functions.update","cloudfunctions.operations.get","firebase.projects.get"]}
[debug] [2024-03-20T07:52:48.365Z] >>> [apiv2][query] POST https://iam.googleapis.com/v1/projects/fuelkdev/serviceAccounts/fuelkdev@appspot.gserviceaccount.com:testIamPermissions [none]
[debug] [2024-03-20T07:52:48.366Z] >>> [apiv2][body] POST https://iam.googleapis.com/v1/projects/fuelkdev/serviceAccounts/fuelkdev@appspot.gserviceaccount.com:testIamPermissions {"permissions":["iam.serviceAccounts.actAs"]}
[debug] [2024-03-20T07:52:49.127Z] <<< [apiv2][status] POST https://iam.googleapis.com/v1/projects/fuelkdev/serviceAccounts/fuelkdev@appspot.gserviceaccount.com:testIamPermissions 200
[debug] [2024-03-20T07:52:49.129Z] <<< [apiv2][body] POST https://iam.googleapis.com/v1/projects/fuelkdev/serviceAccounts/fuelkdev@appspot.gserviceaccount.com:testIamPermissions {"permissions":["iam.serviceAccounts.actAs"]}
[info] 
[info] === Deploying to 'fuelkdev'...
[info] 
[info] i  deploying functions 
[info] Running command: npm --prefix "$RESOURCE_DIR" run build
[info] +  functions: Finished running predeploy script. 
[debug] [2024-03-20T07:52:50.386Z] >>> [apiv2][query] GET https://firebase.googleapis.com/v1beta1/projects/fuelkdev [none]
[debug] [2024-03-20T07:52:50.629Z] <<< [apiv2][status] GET https://firebase.googleapis.com/v1beta1/projects/fuelkdev 200
[debug] [2024-03-20T07:52:50.630Z] <<< [apiv2][body] GET https://firebase.googleapis.com/v1beta1/projects/fuelkdev {"projectId":"fuelkdev","projectNumber":"281795646548","displayName":"fuelkdev","name":"projects/fuelkdev","resources":{"hostingSite":"fuelkdev","storageBucket":"fuelkdev.appspot.com","locationId":"europe-west"},"state":"ACTIVE","etag":"1_a179f940-bfa9-4978-b70f-988077eabd00"}
[info] i  functions: preparing codebase default for deployment 
[info] i  functions: ensuring required API cloudfunctions.googleapis.com is enabled... 
[info] i  functions: ensuring required API cloudbuild.googleapis.com is enabled... 
[info] i  artifactregistry: ensuring required API artifactregistry.googleapis.com is enabled... 
[debug] [2024-03-20T07:52:50.638Z] >>> [apiv2][query] GET https://serviceusage.googleapis.com/v1/projects/fuelkdev/services/cloudfunctions.googleapis.com [none]
[debug] [2024-03-20T07:52:50.639Z] >>> [apiv2][(partial)header] GET https://serviceusage.googleapis.com/v1/projects/fuelkdev/services/cloudfunctions.googleapis.com x-goog-quota-user=projects/fuelkdev
[debug] [2024-03-20T07:52:50.644Z] >>> [apiv2][query] GET https://serviceusage.googleapis.com/v1/projects/fuelkdev/services/runtimeconfig.googleapis.com [none]
[debug] [2024-03-20T07:52:50.645Z] >>> [apiv2][(partial)header] GET https://serviceusage.googleapis.com/v1/projects/fuelkdev/services/runtimeconfig.googleapis.com x-goog-quota-user=projects/fuelkdev
[debug] [2024-03-20T07:52:50.649Z] >>> [apiv2][query] GET https://serviceusage.googleapis.com/v1/projects/fuelkdev/services/cloudbuild.googleapis.com [none]
[debug] [2024-03-20T07:52:50.649Z] >>> [apiv2][(partial)header] GET https://serviceusage.googleapis.com/v1/projects/fuelkdev/services/cloudbuild.googleapis.com x-goog-quota-user=projects/fuelkdev
[debug] [2024-03-20T07:52:50.654Z] >>> [apiv2][query] GET https://serviceusage.googleapis.com/v1/projects/fuelkdev/services/artifactregistry.googleapis.com [none]
[debug] [2024-03-20T07:52:50.654Z] >>> [apiv2][(partial)header] GET https://serviceusage.googleapis.com/v1/projects/fuelkdev/services/artifactregistry.googleapis.com x-goog-quota-user=projects/fuelkdev
[debug] [2024-03-20T07:52:51.587Z] <<< [apiv2][status] GET https://serviceusage.googleapis.com/v1/projects/fuelkdev/services/runtimeconfig.googleapis.com 200
[debug] [2024-03-20T07:52:51.587Z] <<< [apiv2][body] GET https://serviceusage.googleapis.com/v1/projects/fuelkdev/services/runtimeconfig.googleapis.com [omitted]
[debug] [2024-03-20T07:52:51.641Z] <<< [apiv2][status] GET https://serviceusage.googleapis.com/v1/projects/fuelkdev/services/artifactregistry.googleapis.com 200
[debug] [2024-03-20T07:52:51.642Z] <<< [apiv2][body] GET https://serviceusage.googleapis.com/v1/projects/fuelkdev/services/artifactregistry.googleapis.com [omitted]
[info] +  artifactregistry: required API artifactregistry.googleapis.com is enabled 
[debug] [2024-03-20T07:52:51.646Z] <<< [apiv2][status] GET https://serviceusage.googleapis.com/v1/projects/fuelkdev/services/cloudbuild.googleapis.com 200
[debug] [2024-03-20T07:52:51.647Z] <<< [apiv2][body] GET https://serviceusage.googleapis.com/v1/projects/fuelkdev/services/cloudbuild.googleapis.com [omitted]
[info] +  functions: required API cloudbuild.googleapis.com is enabled 
[debug] [2024-03-20T07:52:51.653Z] <<< [apiv2][status] GET https://serviceusage.googleapis.com/v1/projects/fuelkdev/services/cloudfunctions.googleapis.com 200
[debug] [2024-03-20T07:52:51.654Z] <<< [apiv2][body] GET https://serviceusage.googleapis.com/v1/projects/fuelkdev/services/cloudfunctions.googleapis.com [omitted]
[info] +  functions: required API cloudfunctions.googleapis.com is enabled 
[debug] [2024-03-20T07:52:51.657Z] >>> [apiv2][query] GET https://firebase.googleapis.com/v1beta1/projects/fuelkdev/adminSdkConfig [none]
[debug] [2024-03-20T07:52:52.168Z] <<< [apiv2][status] GET https://firebase.googleapis.com/v1beta1/projects/fuelkdev/adminSdkConfig 200
[debug] [2024-03-20T07:52:52.168Z] <<< [apiv2][body] GET https://firebase.googleapis.com/v1beta1/projects/fuelkdev/adminSdkConfig {"projectId":"fuelkdev","storageBucket":"fuelkdev.appspot.com","locationId":"europe-west"}
[debug] [2024-03-20T07:52:52.169Z] >>> [apiv2][query] GET https://runtimeconfig.googleapis.com/v1beta1/projects/fuelkdev/configs [none]
[debug] [2024-03-20T07:52:53.267Z] <<< [apiv2][status] GET https://runtimeconfig.googleapis.com/v1beta1/projects/fuelkdev/configs 200
[debug] [2024-03-20T07:52:53.268Z] <<< [apiv2][body] GET https://runtimeconfig.googleapis.com/v1beta1/projects/fuelkdev/configs {"configs":[{"name":"projects/fuelkdev/configs/mailgun"},{"name":"projects/fuelkdev/configs/fuelkdev_mail"},{"name":"projects/fuelkdev/configs/key"}]}
[debug] [2024-03-20T07:52:53.270Z] >>> [apiv2][query] GET https://runtimeconfig.googleapis.com/v1beta1/projects/fuelkdev/configs/mailgun/variables [none]
[debug] [2024-03-20T07:52:53.272Z] >>> [apiv2][query] GET https://runtimeconfig.googleapis.com/v1beta1/projects/fuelkdev/configs/fuelkdev_mail/variables [none]
[debug] [2024-03-20T07:52:53.277Z] >>> [apiv2][query] GET https://runtimeconfig.googleapis.com/v1beta1/projects/fuelkdev/configs/key/variables [none]
[debug] [2024-03-20T07:52:54.125Z] <<< [apiv2][status] GET https://runtimeconfig.googleapis.com/v1beta1/projects/fuelkdev/configs/mailgun/variables 200
[debug] [2024-03-20T07:52:54.126Z] <<< [apiv2][body] GET https://runtimeconfig.googleapis.com/v1beta1/projects/fuelkdev/configs/mailgun/variables {}
[debug] [2024-03-20T07:52:54.147Z] <<< [apiv2][status] GET https://runtimeconfig.googleapis.com/v1beta1/projects/fuelkdev/configs/key/variables 200
[debug] [2024-03-20T07:52:54.148Z] <<< [apiv2][body] GET https://runtimeconfig.googleapis.com/v1beta1/projects/fuelkdev/configs/key/variables {}
[debug] [2024-03-20T07:52:54.150Z] <<< [apiv2][status] GET https://runtimeconfig.googleapis.com/v1beta1/projects/fuelkdev/configs/fuelkdev_mail/variables 200
[debug] [2024-03-20T07:52:54.151Z] <<< [apiv2][body] GET https://runtimeconfig.googleapis.com/v1beta1/projects/fuelkdev/configs/fuelkdev_mail/variables {}
[debug] [2024-03-20T07:52:54.155Z] Validating nodejs source
[warn] !  functions: package.json indicates an outdated version of firebase-functions. Please upgrade using npm install --save firebase-functions@latest in your functions directory. 
[debug] [2024-03-20T07:52:55.471Z] > [functions] package.json contents: {
  "name": "functions",
  "scripts": {
    "dev:tsc": "tsc --watch --preserveWatchOutput",
    "dev:node": "firebase emulators:start --only functions --debug",
    "dev:esbuild": "pnpm run build --watch",
    "dev": "run-p dev:*",
    "build": "esbuild src/index.ts --bundle --platform=node --outfile=lib/index.js --format=esm --external:./node_modules/*",
    "serve": "firebase emulators:start --only functions",
    "shell": "npm run build && firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions --debug",
    "logs": "firebase functions:log"
  },
  "engines": {
    "node": "20"
  },
  "type": "module",
  "main": "lib/index.js",
  "dependencies": {
    "@google-cloud/cloud-sql-connector": "^1.2.4",
    "@google-cloud/functions-framework": "^3.3.0",
    "dotenv": "^16.4.5",
    "firebase-admin": "^12.0.0",
    "firebase-functions": "^4.8.0",
    "google-auth-library": "^9.7.0",
    "mysql2": "^3.9.2"
  },
  "devDependencies": {
    "@types/node": "^20.11.30",
    "@typescript-eslint/eslint-plugin": "^7.3.1",
    "@typescript-eslint/parser": "^7.3.1",
    "cross-env": "^7.0.3",
    "esbuild": "^0.20.2",
    "eslint": "^8.9.0",
    "eslint-config-google": "^0.14.0",
    "eslint-plugin-import": "^2.25.4",
    "firebase-functions-test": "^3.1.0",
    "npm-run-all": "^4.1.5",
    "typescript": "^5.4.2"
  },
  "private": true
}
[debug] [2024-03-20T07:52:55.475Z] Building nodejs source
[info] i  functions: Loading and analyzing source code for codebase default to determine what to deploy 
[debug] [2024-03-20T07:52:55.477Z] Could not find functions.yaml. Must use http discovery
[debug] [2024-03-20T07:52:55.492Z] Found firebase-functions binary at 'C:\Users\Kehitys\Documents\GitHub\nodeJsSqlConnector\functions\node_modules\.bin\firebase-functions'
[info] Serving at port 8359

[info] undefined

[error] Error: Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information.
    at GoogleAuth.getApplicationDefaultAsync (C:\Users\Kehitys\Documents\GitHub\nodeJsSqlConnector\functions\node_modules\.pnpm\google-auth-library@9.7.0\node_modules\google-auth-library\build\src\auth\googleauth.js:271:15)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async GoogleAuth.getClient (C:\Users\Kehitys\Documents\GitHub\nodeJsSqlConnector\functions\node_modules\.pnpm\google-auth-library@9.7.0\node_modules\google-auth-library\build\src\auth\googleauth.js:695:17)
    at async GoogleAuth.request (C:\Users\Kehitys\Documents\GitHub\nodeJsSqlConnector\functions\node_modules\.pnpm\google-auth-library@9.7.0\node_modules\google-auth-library\build\src\auth\googleauth.js:748:24)
    at async SQLAdminFetcher.getInstanceMetadata (file:///C:/Users/Kehitys/Documents/GitHub/nodeJsSqlConnector/functions/node_modules/.pnpm/@google-cloud+cloud-sql-connector@1.2.4/node_modules/@google-cloud/cloud-sql-connector/dist/mjs/sqladmin-fetcher.js:88:21)
    at async CloudSQLInstance.performRefresh (file:///C:/Users/Kehitys/Documents/GitHub/nodeJsSqlConnector/functions/node_modules/.pnpm/@google-cloud+cloud-sql-connector@1.2.4/node_modules/@google-cloud/cloud-sql-connector/dist/mjs/cloud-sql-instance.js:117:26)
    at async CloudSQLInstance.getCloudSQLInstance (file:///C:/Users/Kehitys/Documents/GitHub/nodeJsSqlConnector/functions/node_modules/.pnpm/@google-cloud+cloud-sql-connector@1.2.4/node_modules/@google-cloud/cloud-sql-connector/dist/mjs/cloud-sql-instance.js:21:9)
    at async CloudSQLInstanceMap.loadInstance (file:///C:/Users/Kehitys/Documents/GitHub/nodeJsSqlConnector/functions/node_modules/.pnpm/@google-cloud+cloud-sql-connector@1.2.4/node_modules/@google-cloud/cloud-sql-connector/dist/mjs/connector.js:46:36)
    at async Connector.getOptions (file:///C:/Users/Kehitys/Documents/GitHub/nodeJsSqlConnector/functions/node_modules/.pnpm/@google-cloud+cloud-sql-connector@1.2.4/node_modules/@google-cloud/cloud-sql-connector/dist/mjs/connector.js:106:9)
    at async file:///C:/Users/Kehitys/Documents/GitHub/nodeJsSqlConnector/functions/lib/index.js:17:18

[debug] [2024-03-20T07:52:56.500Z] Got response code 400; body Failed to generate manifest from function source: Error: Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information.
[error] 
[error] Error: Functions codebase could not be analyzed successfully. It may have a syntax or runtime error

I hope you can help with this issue, as this makes our company unable to use cloud SQL and would require us to move to a different managed database provider, which we do not prefer. If you need any more information, I'm happy to help. Thank you in advance for all the help; it is greatly appreciated.

fuelkoy commented 7 months ago

This can be tackled by lazy init a global pool and connector. As pointed out by @jackwotherspoon

One thing you could try to improve performance would be to lazy init a global pool and connector. This way it is initialized during the first request when you have access to the credentials but then saved for subsequent requests. This is actually mentioned as a tip for Cloud Functions. The only caveat being that you would probably also want to turn on "Always on CPU" so that the Cloud SQL Node Connector's background refreshes have access to CPU and are not throttled (we will be implementing a lazy refresh feature soon so that this is no longer required https://github.com/GoogleCloudPlatform/cloud-sql-nodejs-connector/issues/285)

https://github.com/GoogleCloudPlatform/cloud-sql-nodejs-connector/issues/312#issuecomment-2009503838

I will now close this issue as solved.