41

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.

zeke13210
  • 443
  • 1
  • 4
  • 7
  • Does this answer your question? [How to invoke firebase Schedule functions locally using pubsub emulator](https://stackoverflow.com/questions/62759093/how-to-invoke-firebase-schedule-functions-locally-using-pubsub-emulator) – Viacheslav Dobromyslov Jan 17 '21 at 10:47

4 Answers4

31

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.

JT501
  • 1,407
  • 15
  • 12
  • Thank you very much for this comment. – Max Fahl Oct 21 '21 at 14:51
  • 1
    More info to running on shell [run-firebase-scheduled-functions](https://podzemski.com/2020/10/14/how-to-trigger-and-run-firebase-scheduled-functions-from-localhost/) – Paul Mar 10 '22 at 10:09
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
    })
});
Arno Zwaag
  • 305
  • 2
  • 4
  • 27
    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. – Guilherme Matuella Jun 15 '20 at 17:29
  • 2
    @GuilhermeMatuella it's ok. This workaroud is described here https://stackoverflow.com/a/65759654/1177597 and here https://github.com/firebase/firebase-tools/issues/2034 – Viacheslav Dobromyslov Jan 17 '21 at 10:53
  • I had to instantiate @google-cloud/pubsub with my firebase project ID. – 1252748 Jun 26 '21 at 17:58
  • `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 triggered – Stefano Saitta Jan 31 '22 at 01:14
  • 1
    @stefano I was told the same thing and saw the deprecation warming. Though the documentation is at time of writing not yet updated. – Arno Zwaag Feb 02 '22 at 19:52
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.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • 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. – zeke13210 Apr 16 '20 at 18:12
  • 1
    Yes, you will have to deploy it. – Doug Stevenson Apr 16 '20 at 19:11
  • 21
    if so, what is the pubsub emulator for? – Adi Azarya May 25 '20 at 06:48
  • 1
    @AdiAzarya for pubsubs that are created through topics – Guilherme Matuella Jun 15 '20 at 17:30
  • @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??? – Vixson Nov 29 '20 at 22:09
  • 1
    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. – Viacheslav Dobromyslov Jan 17 '21 at 10:13
  • @Doug Stevenson is right. Please fill out feature request form to have this required feature. – isa Nov 03 '22 at 16:05
11

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...
}
Félix Paradis
  • 5,165
  • 6
  • 40
  • 49