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.
Related
I use the following command to deploy my project, one of the functions being a pub/sub:
firebase deploy --only functions
...and everything happens just fine, but the scheduler job is created a 2nd time, an exact copy of the previous one every time I deploy again.
I don't change the pub/sub function, so I would not necessarily need to include it during deploy, but why is it creating a new scheduler job every time? Neither the function, nor the topic in Pub/Sub is duplicating, only the scheduler job - why?
Here is how the pubsub function looks like, if relevant:
export const scheduledStuff = functions.pubsub
.schedule('0 0 * * *')
.timeZone('America/New_York')
.onRun(() => {
// do stuff
})
Update Jun 17 2022: I didn't specifically mention this, but the code I gave above, I hoped, should have given it away: I'm using the ES6 annotation for the function, ie. use import instead of require for packages, and the function is exported as export const scheduledStuff... instead of exports.scheduledStuff....
My functions are then separated into 2 categories, functions:functions, which are all the functions that are NOT pubsub, and this one pubsub. This is because I wanted to prevent the deployment of the pubsub function to my staging environment, so I'm using firebase deploy --only functions:functions for that one.
For this purpose I have an index file in my main functions directory that looks something like this:
import { default as firstFunction } from './callables/firstFunction.js'
import { default as secondFunction } from './callables/secondFunction.js'
//...
export const functions = {
firstFunction,
secondFunction,
//...
}
import { scheduledStuff } from './pubsub/scheduledStuff.js'
export const pubSubStuff = { scheduledStuff }
I tried to reproduce your case by deploying the below scheduler function which will run every minute and create a pubsub topic and a scheduler job.
In my case, my first deploy firebase deploy –only functions created a pubsub topic firebase-schedule-scheduledFunctionCrontab-us-central1 and a scheduler job firebase-schedule-scheduledFunctionCrontab-us-central.
With the second deployment firebase deploy –only functions, neither a duplicate scheduler job was created nor a duplicate pubsub topic.
My terminal shows the below lines:
functions: updating Node.js 16 function scheduledFunctionCrontab(us-central1)...
✔ functions[scheduledFunctionCrontab(us-central1)] Successful update operation.
The last deployment run got updated but a duplicate is not created. Also the scheduler function keeps updating the last run time and next run time field which confirms that the function is running every minute.
If what you have shared here, is the entire code of your scheduler function, then I think this is a Customer issue/bug.
Still to confirm I would like to have a look at your logs, but if you are confident that this is not an intended behavior (which seems to be according to me) please raise a support ticket with Google Cloud Support or raise a Customer issue in a public issue tracker
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.
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.
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
I am looking for a way to schedule Cloud Functions for Firebase or in other words trigger them on a specific time.
Update 2019-04-18
There is now a very simple way to deploy scheduled code on Cloud Functions through Firebase.
You can either use a simple text syntax:
export scheduledFunctionPlainEnglish =
functions.pubsub.schedule('every 5 minutes').onRun((context) => {
console.log('This will be run every 5 minutes!');
})
Or the more flexible cron table format:
export scheduledFunctionCrontab =
functions.pubsub.schedule('5 11 * * *').onRun((context) => {
console.log('This will be run every day at 11:05 AM UTC!');
});
To learn more about this, see:
The Scheduling Cloud Functions for Firebase blog post introducing the feature.
The documentation on scheduled functions.
Note that your project needs to be on a Blaze plan for this to work, so I'm leaving the alternative options below for reference.
If you want to schedule a single invocation of a Cloud Function on a delay from within the execution of another trigger, you can use Cloud Tasks to set that up. Read this article for an extended example of how that can work.
Original answer below...
There is no built-in runat/cron type trigger yet.
For the moment, the best option is to use an external service to trigger a HTTP function periodically. See this sample in the functions-samples repo for more information. Or use the recently introduced Google Cloud Scheduler to trigger Cloud Functions through PubSub or HTTPS:
I also highly recommend reading this post on the Firebase blog: How to Schedule (Cron) Jobs with Cloud Functions for Firebase and this video: Timing Cloud Functions for Firebase using an HTTP Trigger and Cron.
That last link uses cron-job.org to trigger Cloud Functions, and works for projects that are on a free plan. Note that this allows anyone to call your function without authorization, so you may want to include some abuse protection mechanism in the code itself.
What you can do, is spin up an AppEngine instance that is triggered by cron job and emits to PubSub. I wrote a blog post specifically on that, you might want to take a look:
https://mhaligowski.github.io/blog/2017/05/25/scheduled-cloud-function-execution.html
It is important to first note that the default timezone your functions will execute on is America/Los_Angeles according to the documentation. You may find a list of timezones here if you'd like to trigger your function(s) on a different timezone.
NB!!: Here's a useful website to assist with cron table formats (I found it pretty useful)
Here's how you'd go about it:
(Assuming you'd like to use Africa/Johannesburg as your timezone)
export const executeFunction = functions.pubsub.schedule("10 23 * * *")
.timeZone('Africa/Johannesburg').onRun(() => {
console.log("successfully executed at 23:10 Johannesburg Time!!");
});
Otherwise if you'd rather stick to the default:
export const executeFunction = functions.pubsub.schedule("10 23 * * *")
.onRun(() => {
console.log("successfully executed at 23:10 Los Angeles Time!!");
});