Scheduled function "Failed to update function in region europe-west1" - node.js

I'm trying to deploy a scheduled function but something is not right (I may be doing something wrong).
[error] Error: There was an error deploying functions:
[error] - Error Failed to update function scheduledFunction in region europe-west1
The function in detail:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const { collection, getDocs } = require("firebase/firestore");
admin.initializeApp();
const db = admin.firestore();
exports.scheduledFunction = functions
.region('europe-west1') // because my GCP is eur3 (europe-west) in my firebase config
.pubsub
.schedule("every 5 minutes")
.onRun((context) => {
const coinsRef = db.collection("coins")
console.log(coinsRef)
return null
});
For now, I want to retrieve all of my documents and display it in a console.log.
If I remove the region I get the same error but for us-central. If I specify a time zone rather than a region, the 1st error is displayed.
By removing my coinsRef constant and the region (thus having a totally EMPTY function) it works.
What am I doing wrong?

Related

What format should data sent to a Google Cloud Functions onCall request be in?

I have the most simple Google onCall cloud function:
// [START]
exports.echo = functions.https.onCall(async (data, context) => {
return {
value: "echo"
};
});
// [END]
I submit the following in the Google cloud console test:
{"data":"somedata"}
I am getting the following error:
{"error":{"message":"INTERNAL","status":"INTERNAL"}}
It seems there is an issue with the object that I am passing. Can anyone tell me what the correct format is? What am I missing here?
P.s: I am ultimately trying to connect an onCall function with a client application via Firebase/fire, but that is also giving the same error.
Here's the trace:
/workspace/node_modules/firebase-functions/lib/common/providers/https.js:349:16 at fixedLen (/workspace/node_modules/firebase-functions/lib/providers/https.js:66:41) at /workspace/node_modules/firebase-functions/lib/common/providers/https.js:385:32 at processTicksAndRejections (internal/process/task_queues.js:95:5)
Unhandled error TypeError: res.on is not a function at /workspace/node_modules/firebase-functions/lib/common/providers/https.js:350:17 at new Promise () at /workspace/node_modules/firebase-functions/lib/common/providers/https.js:349:16 at fixedLen (/workspace/node_modules/firebase-functions/lib/providers/https.js:66:41) at /workspace/node_modules/firebase-functions/lib/common/providers/https.js:385:32 at processTicksAndRejections (internal/process/task_queues.js:95:5)
Here's the index.ts:
import * as functions from "firebase-functions";
// The Firebase Admin SDK to access Cloud Firestore.
import admin = require("firebase-admin");
// Triggers
import { echo } from "./triggers/echo"
admin.initializeApp();
// Exports
module.exports = {
// OnCall
echo: functions.https.onCall(echo)
};
A few things:
The arrow function signature was incorrect.
async is not required for this synchronous response.
The correct type of the context parameter is CallableContext:
import * as functions from 'firebase-functions';
export const echo = functions.https.onCall((data:any, context:functions.https.CallableContext) => ({
value: "echo"
}))

Can't get ref on realtime database with emulator

I am trying to attach a listener to realtime database on local emulator with another database selected but it's giving me a weird error.
Here is the code I am using:
const functions = require("firebase-functions");
const handler = async (snapshot, context) => {
console.log(snapshot);
console.log(context);
}
const target = functions.database
.instance("test-db")
.ref("/docs/{docID}")
module.exports = {
create: target.onCreate(handler),
update: target.onUpdate(handler),
delete: target.onDelete(handler),
}
Here is the error that I am getting:
i functions: Beginning execution of "operationsListenerRealtime-update"
! functions: TypeError: Cannot read property 'startsWith' of undefined
at new DataSnapshot (Q:\Projects\test-project\firebase\functions\node_modules\firebase-functions\lib\providers\database.js:270:44)
at RefBuilder.changeConstructor (Q:\Projects\test-project\firebase\functions\node_modules\firebase-functions\lib\providers\database.js:155:28)
at cloudFunction (Q:\Projects\test-project\firebase\functions\node_modules\firebase-functions\lib\cloud-functions.js:133:34)
at C:\Users\duoqu\AppData\Roaming\npm\node_modules\firebase-tools\lib\emulator\functionsEmulatorRuntime.js:592:16
at runFunction (C:\Users\duoqu\AppData\Roaming\npm\node_modules\firebase-tools\lib\emulator\functionsEmulatorRuntime.js:579:15)
at runBackground (C:\Users\duoqu\AppData\Roaming\npm\node_modules\firebase-tools\lib\emulator\functionsEmulatorRuntime.js:591:11)
at processBackground (C:\Users\duoqu\AppData\Roaming\npm\node_modules\firebase-tools\lib\emulator\functionsEmulatorRuntime.js:574:11)
at invokeTrigger (C:\Users\duoqu\AppData\Roaming\npm\node_modules\firebase-tools\lib\emulator\functionsEmulatorRuntime.js:649:19)
at handleMessage (C:\Users\duoqu\AppData\Roaming\npm\node_modules\firebase-tools\lib\emulator\functionsEmulatorRuntime.js:736:15)
at processTicksAndRejections (node:internal/process/task_queues:94:5)
! Your function was killed because it raised an unhandled error.
Clearly I am trying to connect realtime database that is test-db, I also tried writing http://localhost:7002/?ns=test-db but still no luck. I digged deep into the error and saw this thing:
/**
* Interface representing a Firebase Realtime Database data snapshot.
*/
class DataSnapshot {
constructor(data, path, // path will be undefined for the database root
app, instance) {
this.app = app;
if (app && app.options.databaseURL.startsWith('http:')) {
// In this case we're dealing with an emulator
this.instance = app.options.databaseURL;
}
else if (instance) {
// SDK always supplies instance, but user's unit tests may not
this.instance = instance;
}
else if (app) {
this.instance = app.options.databaseURL;
}
else if (process.env.GCLOUD_PROJECT) {
this.instance =
'https://' + process.env.GCLOUD_PROJECT + '.firebaseio.com';
}
this._path = path;
this._data = data;
}
I think the issue may be related to this part of the code
Also the instance function takes parameters like this.
EDIT: I have confirmed that with proper node version it still is giving me the same error.

Nodejs/Mocha - FieldValue.increment - FirebaseError: Function DocumentReference.update() called with invalid data

I have the following code:
NOTE getDb() is wrapper around admin.firestore() see the link in the end of the question for more details.
let wordRef = await getDb().
.collection(DOC_HAS_WORD_COUNT)
.doc(word)
await wordRef.set({ word: word, 'count': 0 })
await wordRef.update('count', admin.firestore.FieldValue.increment(1))
When I execute it I get
FirebaseError: Function DocumentReference.update() called with invalid data. Unsupported field value: a custom object (found in field count)
How do I increment the value in node js, firestore, cloud functions?
NOTE: this problem is specific to Mocha testing, I didn't check but it will probably not fail on real env.
The problem is caused by the code using the real implementation in test, which need to be override by an emulator implementation, as explain in:
https://claritydev.net/blog/testing-firestore-locally-with-firebase-emulators/
Where u can also find the definition of getDb() I used in the code snipet
The following code will replace the firebase admin at run time, only when running in test env.
NOTE: this code is based on https://claritydev.net/blog/testing-firestore-locally-with-firebase-emulators/
and for a full solution, one need to do the same trick for db as explained in the link
//db.js
const admin = require("firebase-admin");
let firebase;
if (process.env.NODE_ENV !== "test") {
firebase = admin
}
exports.getFirebase = () => {
return firebase;
};
exports.setFirebase = (fb) => {
firebase = fb;
};
test:
// package.test.js
process.env.NODE_ENV = "test"
beforeEach(() => {
// Set the emulator firebase before each test
setFirebase(firebase)
});
import:
// package.test.js and package.js (at the top)
const { setFirebase } = require("../db.js")
code:
// package.js
let wordRef = await getDb()
.collection(DOC_HAS_WORD_COUNT)
.doc(word)
await wordRef.set({ word: word, 'count': 0 })
await wordRef.update('count', getFirebase().firestore.FieldValue.increment(1))

Error:"Failed to get the current sub/segment from the context" when use AWS X-ray in Lambda with node.js

I am trying to use implement the AWS X-ray into my current project (using Node.js and Serverless framework). I am trying to wire the X-ray to one of my lambda function, I got the problem of
Error: Failed to get the current sub/segment from the context.
at Object.contextMissingRuntimeError [as contextMissing] (/.../node_modules/aws-xray-sdk-core/lib/context_utils.js:21:15)
at Object.getSegment (/.../node_modules/aws-xray-sdk-core/lib/context_utils.js:92:45)
at Object.resolveSegment (/.../node_modules/aws-xray-sdk-core/lib/context_utils.js:73:19).....
code below:
import { DynamoDB } from "aws-sdk";
import AWSXRay from 'aws-xray-sdk';
export const handler = async (event, context, callback) => {
const dynamo = new DynamoDB.DocumentClient({
service: new DynamoDB({ region })
});
AWSXRay.captureAWSClient(dynamo.service);
try {
// call dynamoDB function
} catch(err) {
//...
}
}
for this problem, I use the solution from
https://forums.aws.amazon.com/thread.jspa?messageID=821510&#821510
the other solution I tried is from https://forums.aws.amazon.com/thread.jspa?messageID=829923&#829923
code is like
import AWSXRay from 'aws-xray-sdk';
const AWS = AWSXRay.captureAWS(require('aws-sdk'));
export const handler = async (event, context, callback) => {
const dynamo = new AWS.DynamoDB.DocumentClient({region});
//....
}
Still not working...
Appreciated to the help of any kind.
As you mention, that happened because you're running locally (using serverless-offline plugin) and the serverless-offline plugin doesn't provide a valid XRAY context.
One possible way to pass this error and still be able to call your function locally is setting AWS_XRAY_CONTEXT_MISSING environment variable to LOG_ERROR instead of RUNTIME_ERROR (default).
Something like:
serverless invoke local -f functionName -e AWS_XRAY_CONTEXT_MISSING=LOG_ERROR
I didn't test this using serverless framework but it worked when the same error occurred calling an amplify function locally:
amplify function invoke <function-name>
I encountered this error also. To fix it, I disabled XRay when running locally. XRay isn't needed when running locally because I can just set up debug log statements at that time.
This is what the code would look like
let AWS = require('aws-sdk');
if (!process.env.IS_OFFLINE) {
const AWSXRay = require('aws-xray-sdk');
AWS = AWSXRay.captureAWS(require('aws-sdk'));
}
If you don't like this approach, you can set up a contextStrategy to not error out when the context is missing.
Link here
AWSXRay.setContextMissingStrategy("LOG_ERROR");
If you don't want the error clogging up your output you can add a helper that ignores only that error.
// Removes noisy Error: Failed to get the current sub/segment from the context due to Xray
export async function disableXrayError() {
console.error = jest.fn((err) => {
if (err.message.includes("Failed to get the current sub/segment from the context")) {
return;
} else {
console.error(err);
}
});
}

Firebase Cloud Function - Unit Testing - Please supply a Firebase app in the constructor for DataSnapshot in order to use the .ref method

I am trying to setup Unit Testing for Firebase cloud functions. I was following these links:
https://firebase.google.com/docs/functions/unit-testing
https://github.com/firebase/functions-samples/blob/4663b4ddfae3ed8f8a110156d60e71f028680ee7/quickstarts/uppercase/functions/test/test.online.js
I am trying to make the sample code run. Code is as follows:
const chai = require('chai');
const sinon = require('sinon');
const admin = require('firebase-admin');
const projectConfig = {
databaseURL : 'https://gr-automation-5e65c.firebaseio.com',
storageBucket : 'gr-automation-5e65c.appspot.com',
projectId : 'gr-automation-5e65c',
};
const test = require('firebase-functions-test')(projectConfig, '../gr-automation-5e65c-firebase-adminsdk-jkdtf-849f3d0f65.json');
test.mockConfig( /* removed for Clarity */ );
const assert = chai.assert;
describe('Cloud Functions', () => {
let myFunctions;
adminInitStub = sinon.stub(admin, 'initializeApp');
admin.initializeApp();
//console.log(test);
before(() => {
myFunctions = require('../lib/index.js');
//console.log(myFunctions);
//console.log(admin);
});
after(() => {
test.cleanup();
admin.database().ref('messages').remove();
});
describe('makeUpperCase', () => {
it('should upper case input and write it to /uppercase', () => {
const snap = test.database.makeDataSnapshot('input', 'messages/11111/original');
const wrapped = test.wrap(myFunctions.makeUppercase);
return wrapped(snap).then(() => {
return admin.database().ref('messages/11111/uppercase').once('value').then((createdSnap) => {
assert.equal(createdSnap.val(), 'INPUT');
});
});
})
});
});
When I run the test, I get the following error:
Cloud Functions
makeUpperCase
Uppercasing undefined input
1) should upper case input and write it to /uppercase
2) "after all" hook
0 passing (364ms)
2 failing
1) Cloud Functions
makeUpperCase
should upper case input and write it to /uppercase:
Error: Please supply a Firebase app in the constructor for DataSnapshot in order to use the .ref method.
at DataSnapshot.get ref [as ref] (node_modules/firebase-functions/lib/providers/database.js:186:19)
at Function.exports.makeUppercase.functions.database.ref.onCreate [as run] (lib/index.js:135:21)
at wrapped (node_modules/firebase-functions-test/lib/main.js:53:30)
at Context.it (test/index.test.js:46:13)
2) Cloud Functions
"after all" hook:
Error: The default Firebase app does not exist. Make sure you call initializeApp() before using any of the Firebase services.
at FirebaseAppError.FirebaseError [as constructor] (node_modules/firebase-admin/lib/utils/error.js:39:28)
at FirebaseAppError.PrefixedFirebaseError [as constructor] (node_modules/firebase-admin/lib/utils/error.js:85:28)
at new FirebaseAppError (node_modules/firebase-admin/lib/utils/error.js:119:28)
at FirebaseNamespaceInternals.app (node_modules/firebase-admin/lib/firebase-namespace.js:105:19)
at FirebaseNamespace.app (node_modules/firebase-admin/lib/firebase-namespace.js:372:30)
at FirebaseNamespace.ensureApp (node_modules/firebase-admin/lib/firebase-namespace.js:388:24)
at FirebaseNamespace.fn (node_modules/firebase-admin/lib/firebase-namespace.js:283:30)
at Context.after (test/index.test.js:31:15)
Any hint on what am I doing wrong?
test.data.makeDataSnapshot has an optional third parameter which is a Firebase app (see https://firebase.google.com/docs/reference/functions/test/test.database#.makeDataSnapshot). However, since you initialized the firebase-functions-test with your project config values, you normally do not need to supply it.
However you have this line:
adminInitStub = sinon.stub(admin, 'initializeApp');
This is causing the next line to initialize a fake app, since initializeApp method was stubbed out to not do anything
This is causing the 2 failures, to fix, remove:
adminInitStub = sinon.stub(admin, 'initializeApp');

Resources