How to trigger Pub/Sub Topic for Firebase Emulator - firebase

Using Firebase Functions, I have code that runs every hour via a Google Cloud Scheduler Job.
It looks like this:
exports.hourly_tick =
functions.pubsub.topic("hourly-tick").onPublish((message, context) => {
return getData()
.then((data) => {
sendEmail(data["message"]);
})
.catch((error) => {
return console.log("🚩 Caught error: ", error);
});
});
I need to be able to test this locally, and am able to start my Firebase Emulator via firebase emulators:start from my terminal. However I do not know how to trigger this function in my local test environment to see logs in the local emulator.
How can I test this scheduled job / firebase function with the local emulator?

This is an ongoing feature request in Firebase tools (see GitHub issue).
As mentioned in the thread:
I think we maybe misled with how we represented #2011. It lets those functions be loaded into the emulator but doesn't actually trigger them on a schedule. Instead you'd have to manually trigger them using a Pub/Sub message.
You can check a workaround on this answer where you'd have to manually trigger a scheduled function using a Pub/Sub message.

Related

Some Cloud Functions formats are not deployed

I guess it must be a silly reason but I don't understand why from these 2 Cloud Functions, only the first one is recognized and deployed when I run the following command:
firebase deploy --only "functions:test1,functions:test2"
The first function that is a simple CRON is well deployed:
exports.test1 = functions
.pubsub.schedule('2,7,12,17,22,27,32,37,42,47,52,57 * * * *')
.timeZone('Europe/Paris')
.onRun((context) => {
console.log('test1');
});
The second one that receives data from a PubSub is never deployed:
exports.test2 = (message, context) => {
const name = message.data
? Buffer.from(message.data, 'base64').toString()
: 'World';
console.log('test2');
};
Do I have to use the gcloud commands to deploy the second one?
The second function test2 which receives data from Pub/Sub is triggered by a Pub/Sub topic. Cloud Functions for Firebase with Pub/Sub trigger which you can find here. As per the linked documentation you should mention the Cloud Functions for Firebase to be triggered by the Pub/Sub topic inside the functions code. The firebase deploy command does not have an option to specify the trigger topic while running the command. So if you want to deploy both the functions at a time then you should change your code to include the trigger topic as following -
exports.test2 = functions.pubsub.topic('topic-name').onPublish((message) => {
const name = message.data
? Buffer.from(message.data, 'base64').toString()
: 'World';
console.log(name);
});
topic-name is your Pub/Sub topic name.
If you don’t want to deploy both the functions at a time, then you can deploy the test2 function using gcloud with the code you have written and specify the trigger topic name while running the command, as mentioned here.

Firebase functions logging does not work from non-callable functions

I'm getting started with Firebase Functions. I made a simple callable function:
exports.myCallable = functions.https.onCall((data, context) => {
console.log('I am here.');
functions.logger.log('I am here 2.');
});
As expected, I see these logs in the Logs tab in Firebase Console.
However, I also made this function, which should trigger when the user creates their account.
exports.setGroupAfterAuth = functions.auth.user().onCreate((user) => {
console.log('I am here 3.');
functions.logger.log('I am here 4.');
});
In this case, I see that the function was called in Firebase Console, but I do not see my logs.
Why do the logs appear in Firebase Console for the first function but not the second, and what can I do to make them appear in the second?
It's not possible to use the Firebase Functions client SDK to invoke an auth onCreate function.
Auth onCreate functions can only be invoked by actually creating a new user account. They cannot be invoked directly from your app.
The client SDK can only be used to invoke callable functions, as described in the linked documentation. The funciton must be declared with functions.https.onCall.

firebase scheduled cloud function not being called [duplicate]

I am working on cloud functions especially schedule functions. I need to trigger a function periodically each 5 minutes, but in only test step. I need to run it on pubsub emulator without deploying it.
How to do it?
I tried to use firebase shell, but it triggered only once
exports.scheduledFunctionPlainEnglish =functions.pubsub.schedule('every 2 minutes')
.onRun((context) => {
functions.logger.log("this runs every 2 minutes")
return null;
})
Scheduled functions are loaded to the Cloud Functions emulator runtime and are bound to the PubSub emulator topic.
But as #samstern said (https://github.com/firebase/firebase-tools/issues/2034):
you'd have to manually trigger them using a Pub/Sub message.
You can do it like this:
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import { PubSub } from '#google-cloud/pubsub';
if (!admin.apps.length) {
admin.initializeApp();
}
const pubsub = new PubSub({
apiEndpoint: 'localhost:8085' // Change it to your PubSub emulator address and port
});
setInterval(() => {
const SCHEDULED_FUNCTION_TOPIC = 'firebase-schedule-yourFunctionName';
console.log(`Trigger sheduled function via PubSub topic: ${SCHEDULED_FUNCTION_TOPIC}`);
const msg = await pubsub.topic(SCHEDULED_FUNCTION_TOPIC).publishJSON({
foo: 'bar',
}, { attr1: 'value1' });
}, 5 * 60 * 1000); // every 5 minutes
Additional info about this concept (thanks to #kthaas):
https://github.com/firebase/firebase-tools/pull/2011/files#diff-6b2a373d8dc24c4074ee623d433662831cadc7c178373fb957c06bc12c44ba7b
https://github.com/firebase/firebase-tools/pull/2011/files#diff-73f0f0ab73ffbf988f109e0a4c8b3b8a793f30ef33929928a892d605f0f0cc1f
As you said, you can use firebase shell to run your function once.
And in firebase shell, you can use NodeJS commands.
Use setInterval
Inside firebase functions:shell, use setInterval to run your function every 2 minutes.
user#laptop:~$ firebase functions:shell
✔ functions: functions emulator started at http://localhost:5000
i functions: Loaded functions: myScheduledFunction
firebase > setInterval(() => myScheduledFunction(), 120000)
> this runs every 2 minutes
Single line script
Since version 8.4.3 of firebase-tools, and especially this PR, the pipe solution does not work anymore.
In Bash, you can even pipe the setInterval command to firebase shell
user#laptop:~$ echo "setInterval(() => myScheduledFunction(), 120000)" | firebase functions:shell
For those of you seeing this in 2023, it's still not supported.
My solution was to abstract the code that does the "work" out of functions.pubsub.schedule and into their own functions. Then create a separate file (i added it at the top of the functions folder) with a setInterval inside it that fires the aforementioned abstracted function.
For example, somewhere in your code:
exports.myScheduledFunctionCode = () => {
console.log('why, hello there interval');
}
And in the timers.js (for example) file at the top of the /functions directory:
setInterval(() => {
myScheduledFunctionCode();
}, 60000);
Then, you can fire up your Firebase Emulator suite. In another Terminal session, just run a vanilla $ node functions/timers.js. Now your scheduled function code is running, and your whole emulator suite too.
Hope this helps someone!
This is currently not supported for scheduled functions. The documentation states:
Using the shell, you mock data and perform function calls to simulate interaction with products that the Emulator Suite does not currently support: Storage, PubSub, Analytics, Remote Config, Storage, Auth, and Crashlytics.
Scheduled functions are an unsupported extension of pubsub triggers.
Feel free to file a feature request with Firebase support.

Firebase Emulator: using PubSub in Functions

I am trying to run my Firebase functions locally through the emulator. I have built a architecture where chains of processes are invoked by PubSub events. When trying to invoke these events, the emulator logs give me this:
Sorry, we cannot connect to Cloud Services without a project ID. You may specify one with an environment variable named "GOOGLE_CLOUD_PROJECT".
I am running the emulators with --project {projectID}. Also I am constructing my PubSub events like this:
const pubsub = new PubSub({ projectId: getRealtimeDatabase().app.options.projectId })
I am using package "#google-cloud/pubsub": "^0.22.2", and I am importing PubSub like import { PubSub } from '#google-cloud/pubsub';
What do I have to do to make PubSub invoke new events? Thanks!
Turned out getRealtimeDatabase().app.options.projectId was undefined. I retrieved my projectId elsewhere. With the correct projectId, the code above works.

Google Cloud Functions Cron Job Not Working

I am trying to set up a scheduled function in Firebase Cloud Functions. As a simple test, I have tried to recreate the sample shown on the documentation page:
const functions = require('firebase-functions')
exports.scheduledFunction = functions.pubsub
.schedule('every 5 minutes')
.onRun(context => {
console.log('This will be run every 5 minutes!')
return null
})
However, when I run firebase serve --only functions, I get the following error:
function ignored because the pubsub emulator does not exist or is not running.
Any idea why I get this message and how I can fix it?
From the documentation on Firebase's local emulator:
The Firebase CLI includes a Cloud Functions emulator which can emulate the following function types:
HTTPS functions
Callable functions
Cloud Firestore functions
So the local Firebase emulators don't currently support pubsub, and the error message seems to confirm that. So for the moment, you can't run pubsub triggered Cloud Functions locally.
A feature request for adding PubSub support to the emulator was filed. You might want to read up (and possibly comment) there, as the direction taken may or may not match with your needs.
The local shell does support invoking pubsub functions. That is of course quite different, but might be useful as a workaround for the moment.
For what it is worth, you need to enable the pubsub emulator in firebase. Add this to your emulators block:
{
"emulators": {
"pubsub": {
"port": 8085
},
}
}
Even then, it only creates the definition. The emulator doesn't support running the function on a schedule.
To simulate that behavior, I define a HTTP trigger, in which I manually send a message to the topic. For a schedule topic, it is firebase-schedule-<functionName>. In your case it will be firebase-schedule-scheduledFunction.
Sample code looks like:
const pubsub = new PubSub()
export const triggerWork = functions.https.onRequest(async (request, response) => {
await pubsub.topic('firebase-schedule-scheduledFunction').publishJSON({})
response.send('Ok')
})
Then on the command line, I trigger the HTTP function on a schedule.
while [ 1 ];
do wget -o /dev/null -O /dev/null http://localhost:5001/path/to/function/triggerWork;
sleep 300;
done

Resources