Reputation: 159
My schedule Cloud Function is running on schedule, but not successfully writing to my Firestore instance. The code successfully writes to the FirestoreDB when I trigger it as an HTTP request locally. But it does not appear to be writing to Firestore once deployed with PubSub scheduling logic added.
The Function logs in GCP are showing a finished status of "ok".
Wondering if I'm doing something works in JS, but GCP or Pubsub doesn't like, even though it's technically valid JS?
Any help or direction is appreciated.
const admin = require("firebase-admin");
const request = require("request");
const functions = require("firebase-functions");
const serviceAccount = require("......");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
});
const db = admin.firestore();
exports.scheduledPRRfunction = functions.pubsub
.schedule("every 2 minutes")
.timeZone("America/New_York")
.onRun(((context) => {
const Options = {
"method": "GET",
"url": "...",
"headers": {
"Cookie": ".....",
},
};
db.collection("myCollectionName").get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
const documentIds = doc.id;
// Delete Documents
db.collection("myCollectionName")
.doc(documentIds).delete().then(() => {
}).catch((error) => {
console.log("Error removing document: ", error);
});
});
});
// Write Documents
request(Options, function(error, response) {
if (error) throw new Error(error);
const apiResponse = JSON.parse(response.body);
const parsedResponse = apiResponse["news_results"];
for (let i = 0; i < parsedResponse.length; i++) {
// console.log(i);
db.collection("myCollectionName").add(parsedResponse[i]);
}
});
}));
Upvotes: 0
Views: 718
Reputation: 83093
request
supports callback interfaces natively but does not return a promise, which is what you must do within a Pub/Sub Cloud Function (as well as within background Cloud Functions).
This is explained in the official Firebase video series here: https://firebase.google.com/docs/functions/video-series/. In particular watch the three videos titled "Learn JavaScript Promises" (Parts 2 & 3 especially focus on background triggered Cloud Functions, but it really worth watching Part 1 before).
There is a request-promise
library that could be used instead, but since Feb 11th 2020 request
is fully deprecated, so I would recommend using axios.
The following code should do the trick (untested):
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const axios = require('axios');
admin.initializeApp();
const db = admin.firestore();
exports.scheduledPRRfunction = functions.pubsub
.schedule("every 2 minutes")
.timeZone("America/New_York")
.onRun(async (context) => {
try {
const querySnapshot = await db.collection("myCollectionName").get();
const promises = querySnapshot.docs.map(doc => db.collection("myCollectionName").doc(doc.id).delete());
await Promise.all(promises);
const options = {
"method": "get",
"url": "...",
"headers": {
"Cookie": ".....",
},
};
const axiosResponse = await axios(options);
const apiResponse = JSON.parse(axiosResponse.data);
const parsedResponse = apiResponse["news_results"];
const docCreationPromises = parsedResponse.map(response => db.collection("myCollectionName").add(parsedResponse))
await Promise.all(docCreationPromises);
return null;
} catch (error) {
console.log(error);
return null;
}
});
Note that:
async/await
, to make it easier to write the asynchronous codePromise.all()
.In addition, note that since Version 1.0.0 of the Firebase SDK for Cloud Functions, firebase-admin
shall be initialized without any parameters within the Cloud Functions runtime, as follows:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
Upvotes: 3