How to use firebase emulators pubsub to test timed functions locally?
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.
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
})
});
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.
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...
}