Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Switch Firebase Function to Gen-2

i just saw that we have Cloud Functions 2nd generation which looks great: https://cloud.google.com/functions/docs/2nd-gen/overview

But how can i switch my 1nd gen function to be 2nd gen? I see that i can create a new function as 2nd gen like this:

const functions = require('@google-cloud/functions-framework');

functions.http('helloHttp', (req, res) => {
 res.send(`Hello ${req.query.name || req.body.name || 'World'}!`);
});

but what about old functions? Is there a way or i will have to delete and re-create them one-by-one?

like image 748
Ivan Chernykh Avatar asked Dec 07 '25 22:12

Ivan Chernykh


2 Answers

Cloud Function Gen2 is only available for the product Cloud Functions, not Firebase functions.
Firebase functions use the library firebase-functions while Cloud Functions uses @google-cloud/functions-framework.
From the Google Cloud console both functions will appear the same but if you try to deploy a Cloud Function gen2 over a Cloud Function gen1, you will receive the following error:

Failed to create function, function projects/[PROJECT_NUMBER]/locations/[LOCATION]/functions/[FUNCTION_NAME] already exists under 'Gen 1' environment. Please delete conflicting function first or deploy the function with a different name.

You will need to migrate completely from Firebase functions to brand-new created Cloud Functions gen2.

like image 67
Antonio Ramirez Avatar answered Dec 09 '25 15:12

Antonio Ramirez


Things may have changed as of August 9, 2022 when Cloud Functions 2nd Gen become Generally Available, so I'll document what worked for me in a TypeScript project.

1st Gen

Client

"firebase": "9.9.3"

import { httpsCallable } from "firebase/functions";
import { AddTwoNumbersInputParams, AddTwoNumbersInputResult } from "./util/shared/my-types";

// ...

const addTwoNumbersFuncCallable = httpsCallable<AddTwoNumbersInputParams, AddTwoNumbersInputResult>(
    firebaseFunctions,
    "addTwoNumbersFunc",
);

const result = await addTwoNumbersFuncCallable({
    firstNum: 3,
    secondNum: 5
});

console.log("Result", result.data);

Server

"firebase-functions": "^3.21.0"

import * as functions from "firebase-functions";
import { AddTwoNumbersInputParams, AddTwoNumbersInputResult } from "./util/shared/my-types";

// ...

export const addTwoNumbersFunc = functions.https.runWith({ memory: "1GB" }).onCall((params: AddTwoNumbersInputParams, ctx): AddTwoNumbersInputResult => {
    
    if (!ctx.auth) {
        throw new functions.https.HttpsError("unauthenticated", "You must be logged in to call server-side functions");
    }


    return { result: params.firstNum + params.secondNum };
}

Shared

To share the TypeScript interfaces AddTwoNumbersInputParams and AddTwoNumbersInputResult across my client and server code, I created a symlink to a directory util/shared containing the following definitions in a file called my-types.ts:

export interface AddTwoNumbersInputParams {
    firstNum: number
    secondNum: number
}

export interface AddTwoNumbersInputResult {
    result: number
}

2nd Gen

Client

"firebase": "9.9.3"

import { httpsCallableFromURL } from "firebase/functions"; // see note1, note2, note3 below 

// ...

const addTwoNumbersFuncCallable = httpsCallableFromURL<AddTwoNumbersInputParams, AddTwoNumbersInputResult>(
    firebaseFunctions,
    "https://addtwonumbersfunc-fri67ycgta-uc.a.run.app",  // see note1, note2, note3 below 
);

const result = await addTwoNumbersFuncCallable({
    firstNum: 3,
    secondNum: 5
});

console.log("Result", result.data);

note1: The callable documentation and http-events documentation both say that the firebase deploy command should output the URL but I did not see it. I obtained it instead by going here:

  1. Firebase Console
  2. Click your project
  3. Click Functions (in Table of Contents on left-hand-side but click "All products" if you don't see it and then click Functions)
  4. Copy the URL for your function in the Trigger column; it should be of the form https://<lowercase_func_name>-<random-hash>-<region>.a.run.app

note2: At first I was worried 2nd Gen functions would introduce a manual step into my Continuous Integration pipeline because they output a URL now (or so it said). With several Firebase projects representing different stages to promote to production (Google's recommendation), I thought I would have a new hassle to copy and paste the URL for each deployment of the 2nd Gen Functions. Luckily it's not as bad as I thought because "the URL remains stable after deployment". So I only had to deploy once to get the URL, plug it into my client code, and then it remained the same for each deployment thereafter. That said, it's still a different URL for each of my Firebase Projects. So I will have to do more work to promote to production. But maybe they'll fix this because they said "In a future release, 2nd gen function URLs will be updated to be both stable and deterministic.".

note3: I found the URL thing so combersome that I tried without it and had success with the Firebase Functions emulator but not on a real Firebase Project. With the emulator, I was litterally able to continue using the httpsCallable() function that accepts a name of the function instead of the httpsCallableFromURL() function that requires a URL. It worked on the emulator, but not with a real Firebase Project.

Server

"firebase-functions": "^3.21.0"

import * as functionsV2 from "firebase-functions/v2";
import {CallableRequest} from "firebase-functions/lib/common/providers/https";
import {HttpsOptions} from "firebase-functions/lib/v2/providers/https";

// ... 

const httpsOptions: HttpsOptions = {
    memory: "16GiB"  // see note4 below
};


// see note5 below
export const addtwonumbersfunc = functionsV2.https.onCall(httpsOptions, (request: CallableRequest<AddTwoNumbersInputParams>): AddTwoNumbersInputResult => {
    if (!request.auth) {
        throw new functionsV2.https.HttpsError("unauthenticated", "You must be logged in to call server-side functions");
    }

    return { result: request.data.firstNum + request.data.secondNum };
});


note4: The runWith() syntax for setting the memory (etc.) seems to have changed to an HttpsOptions object that you pass to the onCall() that accepts HttpsOptions such as memory. One of the exciting things about 2nd Gen is it offers higher memory allocations than 1st Gen so I have demonstrated that here but increasing from "1GB" to "16GiB" (note also the change from "GB" to "GiB").

note5: "Function names are restricted to lowercase letters, numbers, and dashes." but hopefully coming soon is "Support for using capital letters in function names."

Shared

No changes required

like image 20
Michael Osofsky Avatar answered Dec 09 '25 16:12

Michael Osofsky