How to use firebase emulators pubsub to test timed functions locally?
Asked Answered
C

4

42

I'm using firebase for a project and am working on creating a schedule function using the following code. I want to log a message every minute this runs.

export const timedQuery = functions.pubsub.schedule('1 * * * *').onRun((context) => {
console.log("I am running")
return null;
})

I have the main logic of the code working under an http function and would like to see if this works locally before deploying to production. Going through firebase docs I've downloaded all of the firebase emulators and use "firebase emulators:start" to get them running. From the logs it looks like my pubsub emulator starts successfully at localhost:8085 and pubsub function is initialized however even after waiting for 2 - 3 minutes nothing prints out. Is it possible to test scheduled functions locally?

Also I created this without using google cloud scheduler since I'm only on firebase.

Cancellate answered 16/4, 2020 at 15:14 Comment(1)
Does this answer your question? How to invoke firebase Schedule functions locally using pubsub emulatorJuliennejuliet
P
26

The Firebase local emulator currently doesn't simulate the actual scheduled functions. The documentation says:

The Firebase CLI includes a Cloud Functions emulator which can emulate the following function types:

  • HTTPS functions
  • Callable functions
  • Cloud Firestore functions

I suggest filing a feature request with Firebase support.

When you deploy a scheduled function, you are actually using Google Cloud Scheduler behind the scenes. The details are managed for you. As stated in the documentation:

If you want to schedule functions to run at specified times, use functions.pubsub.schedule().onRun() This convenience method creates a Google Cloud Pub/Sub topic and uses Google Cloud Scheduler to trigger events on that topic, ensuring that your function runs on the desired schedule.

I suggest refactoring your function's code into a method that you can test by invoking it directly using a test framework of your choice. You could also temporarily wrap it in an HTTP function and invoke it that way.

Planometer answered 16/4, 2020 at 15:20 Comment(7)
Ok so just so I understand. If I want to see my scheduled function working real-time I would need to deploy it using "firebase deploy" correct? Since there is no current functionality to use firebase emulators to test locally.Cancellate
Yes, you will have to deploy it.Planometer
if so, what is the pubsub emulator for?Frulla
@AdiAzarya for pubsubs that are created through topicsHeuristic
@AdiAzarya That was a very good question. I mean the option was right there when running init and yet the feature doesn't still would locally, What's the need???Orchestrate
This answer is only partially correct. You may use PubSub emulator but without a scheduler. And yes, it's better when your function logic is written as a separate plain JS/TS function or as a class method and then just executed with the Cloud Function trigger binding.Juliennejuliet
@Doug Stevenson is right. Please fill out feature request form to have this required feature.Adellaadelle
F
39

Workaround

The PubSub emulator still not yet support scheduled functions.

But you can use firebase functions:shell and setInterval to simulate scheduler.

NOTE: Please ensure you are running the firebase emulator locally, or the shell may call the functions in Production !!

firebase functions:shell

firebase > setInterval(() => yourScheduledFunc(), 60000)

Don't exit, then it will run your functions every 60 seconds.

NOTE: functions ran in shell will not be shown in emulator's log.

Flied answered 3/10, 2021 at 10:59 Comment(3)
Thank you very much for this comment.Middleman
More info to running on shell run-firebase-scheduled-functionsImpi
Great answer, I did not know we can call functions from the shell. I had to do setInterval(() => yourScheduledFunc({}), 60000) otherwise I get an Invalid Argument error. But that's an easy fix.Kung
H
28

Actually there is a Firebase PubSub emulator. To enable it you need to have the recent CLI installed (it's in 8.2.0 for sure)

  • Rerun Firebase Init
  • Select Emulators (spacebar)
  • Select PubSub (and others you wish)
  • Configure your desired dev ports
  • Have the CLI install the emulators

Create a test script locally to submit PubSub messages into the queue:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

const { PubSub } = require('@google-cloud/pubsub');
const pubsub = new PubSub();

exports.pubsubWriter = functions.https.onRequest(async (req, res) => {
    console.log("Pubsub Emulator:", process.env.PUBSUB_EMULATOR_HOST);

    const msg = await pubsub.topic('test-topic').publishJSON({
        foo: 'bar',
        date: new Date()
    }, { attr1: 'value' });

    res.json({
        published: msg
    })
});
Hulsey answered 30/4, 2020 at 14:8 Comment(5)
You're partially correct, because it works only for pubsub that are created through topics - and not for the scheduled ones, which the OP asked for.Heuristic
@GuilhermeMatuella it's ok. This workaroud is described here https://mcmap.net/q/391406/-how-to-invoke-firebase-schedule-functions-locally-using-pubsub-emulator and here github.com/firebase/firebase-tools/issues/2034Juliennejuliet
I had to instantiate @google-cloud/pubsub with my firebase project ID.Snare
publishJSON seems to be deprecated right now you should use publishMessage({ json: {} }) instead. Also remember to always publish on the topic if not, the function will not be triggeredCountess
@stefano I was told the same thing and saw the deprecation warming. Though the documentation is at time of writing not yet updated.Hulsey
P
26

The Firebase local emulator currently doesn't simulate the actual scheduled functions. The documentation says:

The Firebase CLI includes a Cloud Functions emulator which can emulate the following function types:

  • HTTPS functions
  • Callable functions
  • Cloud Firestore functions

I suggest filing a feature request with Firebase support.

When you deploy a scheduled function, you are actually using Google Cloud Scheduler behind the scenes. The details are managed for you. As stated in the documentation:

If you want to schedule functions to run at specified times, use functions.pubsub.schedule().onRun() This convenience method creates a Google Cloud Pub/Sub topic and uses Google Cloud Scheduler to trigger events on that topic, ensuring that your function runs on the desired schedule.

I suggest refactoring your function's code into a method that you can test by invoking it directly using a test framework of your choice. You could also temporarily wrap it in an HTTP function and invoke it that way.

Planometer answered 16/4, 2020 at 15:20 Comment(7)
Ok so just so I understand. If I want to see my scheduled function working real-time I would need to deploy it using "firebase deploy" correct? Since there is no current functionality to use firebase emulators to test locally.Cancellate
Yes, you will have to deploy it.Planometer
if so, what is the pubsub emulator for?Frulla
@AdiAzarya for pubsubs that are created through topicsHeuristic
@AdiAzarya That was a very good question. I mean the option was right there when running init and yet the feature doesn't still would locally, What's the need???Orchestrate
This answer is only partially correct. You may use PubSub emulator but without a scheduler. And yes, it's better when your function logic is written as a separate plain JS/TS function or as a class method and then just executed with the Cloud Function trigger binding.Juliennejuliet
@Doug Stevenson is right. Please fill out feature request form to have this required feature.Adellaadelle
S
12

Reruning firebase init didn't work for me because reasons.

I ended up manually modifying the firebase.json file,

Quoting the related docs:

Change emulator ports by running firebase init emulators or by editing firebase.json manually.

// firebase.json
{
  "hosting": {
    // stuff...
  },
  "functions": {
    // stuff...
  },
  "emulators": {
    "functions": {
      "port": 5001
    },
    "hosting": {
      "port": 5000
    },
    "ui": {
      "enabled": true
    },
    "firestore": {
      "port": 8080
    },
    // * * * * * * * * *THIS👇 * * * * * * * * * * * * * * * * * * * * * * * 
    "pubsub": {
      "port": "8085"
    }
    // * * * * * * * * *THIS👆 * * * * * * * * * * * * * * * * * * * * * * * 
  },
  // more stuff...
}
Semiyearly answered 20/9, 2021 at 20:32 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.