0
votes

I'm trying to integrate Firebase Cloud Functions into an Android app. I'm new in Cloud Functions and Node.js.

So, I have the below simple node.js code to save data in Firestore database:

'use strict';

const admin = require('firebase-admin');
const functions = require('firebase-functions');
admin.initializeApp(functions.config().firebase);
const Firestore = require('@google-cloud/firestore');


exports.saveData = functions.https.onRequest((request, response) => {

    var firestoreDB = new Firestore({
        projectId: 'my_project_id',
        keyFilename: 'my_key_file_name'
    });

    const line1 = request.body.line1;
    const line2 = request.body.line2;

    var data = {
        name: line1,
        number: line2
    };

    return firestoreDB.collection('myData').doc('firstDoc')
    .add( data )
    .then(ref => {
        console.log('Data saved.');
        response.end();
    });
});

This code is working fine, but being executed twice. It writes the data into DB twice, it logs every single log twice in Firebase console log screen.

I have tried another function to send a message using FCM from Android device to Android device, it also send the message twice.

I checked Android side to make sure it's triggered once. I'm wondering if there is anything I'm missing out to make it work. Any help or suggestions appreciated.

2
Since i don't see any response in your code and it ends with timeout it could be that your device sends another request after the timeout. I had this issue with a browser which after the timeout sent another request. Aren't you missing something like response.status(200).send('OK') after console.log('Data saved.');?? I'm not familiar with firebase functions though. Update: Just found an example here - Molda
I'm not sure if it's the root cause, but you should resolve the premise with res.redirect(), res.send(), or res.end(). - Eric Haskins
@Molda, I don't think my device sends another request after timeout. The above timeout messages appear at the same time after certain amount of time. I've seen 'response.status(200).send('OK')' in some tutorials, what does it do and where in the code it should go? Thanks. - Dan
@Dan, can you direct the traffic from your device though a proxy, like Fiddler, to verify the app is only making one request. - Eric Haskins

2 Answers

2
votes

So, the real problem was in Volley on Android (Java) side. By default, Volley makes the second attempt to reach the server if it doesn't hear back in 2.5 sec. Because I have had heavy operations and sometimes a drop in Internet speed, it always took more that 2.5 sec to respond back.

If anyone is facing similar issue, just double check Volley and make sure to add the following at the end of Volley request

      stringRequest.setRetryPolicy(
            new DefaultRetryPolicy(
                    15000,   // timeout timimg of 15 sec
                    0,       // number of retries. By default the number is 1
                    DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
    // Add the request to the RequestQueue.
    MySingleton.getInstance().addToRequestQueue(stringRequest);
1
votes

You are not sending response from API so browser not getting any response and it retry the API untill timeout of 60 sec.

response.status(200).send('OK');

Enter this above line as show below -

exports.saveData = functions.https.onRequest((request, response) => {

    var firestoreDB = new Firestore({
        projectId: 'my_project_id',
        keyFilename: 'my_key_file_name'
    });

    const line1 = request.body.line1;
    const line2 = request.body.line2;

    var data = {
        name: line1,
        number: line2
    };

    return firestoreDB.collection('myData').doc('firstDoc')
    .add( data )
    .then(ref => {
        console.log('Data saved.');
        response.status(200).send('OK');
    });
});