george43g / better-firebase-functions

This repo provides functionality for a better way of organising files, imports and function triggers in Firebase Cloud Functions
Mozilla Public License 2.0
179 stars 15 forks source link

Only one function gets deployed #10

Closed zanesc closed 2 years ago

zanesc commented 4 years ago

When I run firebase deploy only the very first function in the project structure is getting deployed. I am using the exact project structure that you recommend in your Medium article. If I uncomment the function that is being deployed successfully, the very next function in the project structure which is located in a different sub-directory to the initial function that is being deployed gets deployed... and so on. So exportFunctions is able to traverse through my entire project directory however it only deploys the very first function it finds.

zanesc commented 4 years ago

Finally got it working properly! The issue here was that I was initializing the app with initializeApp in multiple places. However, it gave no errors. I found this by running 'firebase serve' which produced the necessary errors. I moved initializeApp to my index.ts file and all of my functions now deploy. Thank you very much for your hard work.

Would this be the recommended place to initialize admin with this module?

george43g commented 4 years ago

Finally got it working properly! The issue here was that I was initializing the app with initializeApp in multiple places. However, it gave no errors. I found this by running 'firebase serve' which produced the necessary errors. I moved initializeApp to my index.ts file and all of my functions now deploy. Thank you very much for your hard work.

Would this be the recommended place to initialize admin with this module?

I'm so glad you asked. I've been working on releasing the second part to a medium series that addresses this exact issue.

For the time being, I'll post a code snippet for you.

// Think of this module as the interface between Firebase SDKs and your app - All code to abstract away loading and initialising Firebase Libraries and services goes here. Your setup may vary.
import { firestore, initializeApp, apps, auth } from 'firebase-admin';

/**
 * Internal
 * Checks to see if Firebase App has been initialised (admin)
 * @returns `boolean` false if more than one initialised, otherwise true
 * @hidden
 */
const _notInit = (): boolean => apps.length === 0;
let db: FirebaseFirestore.Firestore;
let fAuth: auth.Auth;

/**
 * Will ensure firebase app is initialised
 * @returns `void`
 */
export const initAdmin = () => {
  if (_notInit()) initializeApp();
};

/**
 * Makes sure firebase app is initialised and returns Firestore object
 */
// tslint:disable-next-line: ban-comma-operator no-void-expression
export const getDb = (): FirebaseFirestore.Firestore => (initAdmin(), db || (db = firestore()));

/**
 * Makes sure firebase app is initialised and returns Auth service
 */
// tslint:disable-next-line: ban-comma-operator no-void-expression
export const getAuth = (): auth.Auth => (initAdmin(), fAuth || (fAuth = auth()));

You're supposed to initialise firebase at the top of each module that uses it. If unit testing, you'll need an init statement at the top of each file. However, if you try initialise more than once, you'll get an error. I won't go into detail as to why this happens, but some people just put their initialise statement in a try-catch block, which is ugly. The above snippet checks if firebase has been initialised, will only initialise it once, caches the db or auth object, and returns the same instance wherever you may need it.

Simply import getDb or getAuth wherever you need them, and use at the top of each module to get your db or auth instance.

zanesc commented 3 years ago

Thank you, I have implemented this in my project.

What should be the average cold start time for a simple cloud function? I'm still seeing ~3secs/function which is not acceptable in my use case.

Is the cold start supposed to happen for every cloud function? Or should it only happen when the first function is called and then all other functions should run smoothly?

My use case is that I have built a multi-player online card game which has many callable functions per round and with the cold starts the first round is mostly just waiting on the various cloud functions to cold start. From the second round on, once all of the functions have started, it's smooth.

bkr32 commented 3 years ago

thanks for the snippet, helped me sort out the single deploying function, however i later faced a issue where firestore throws

Exception from a finished function: Error: The default Firebase app does not exist. Make sure you call initializeApp() before using any of the Firebase services.

is the snippet to only be used in index.ts or every module that uses those firebase functions? @george43g

george43g commented 2 years ago

The above snippet is a module that you can import getDb and getAuth to reliably initialise and provide you with those services.