Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error: Can't set headers after they are sent in firebase cloud function

I am using Firebase database for my android application. I am using cloud functions feature of it. I have coded functions and trying to test it on local machine.

I am running this command to test it, cloud functions works well on firebase server not on localhost. Below commands sends an error

firebase serve --only functions

> firebase serve --only functions

=== Serving from 'D:\Firebase'...

i  functions: Preparing to emulate HTTPS functions. Support for other event types coming soon.
Warning: You're using Node.js v7.10.0 but Google Cloud Functions only supports v6.11.1.
Server#addProtoService is deprecated. Use addService instead
+  functions: getUsers: http://localhost:5002/xyz/us-central1/getUsers
info: User function triggered, starting execution
info: Execution took 60022 ms, finished with status: 'timeout'
info: Execution took 60022 ms, finished with status: 'crash'
Error: Can't set headers after they are sent.
    at ServerResponse.setHeader (_http_outgoing.js:371:11)
    at ServerResponse.header (C:\Users\williams\AppData\Roaming\npm\node_modules\firebase-tools\node_modules\express\lib\response.js:730:10)
    at ServerResponse.send (C:\Users\williams\AppData\Roaming\npm\node_modules\firebase-tools\node_modules\express\lib\response.js:170:12)
    at ServerResponse.json (C:\Users\williams\AppData\Roaming\npm\node_modules\firebase-tools\node_modules\express\lib\response.js:256:15)
    at ProxyServer.Supervisor._proxy.on (C:\Users\williams\AppData\Roaming\npm\node_modules\firebase-tools\node_modules\@google-cloud\functions-emulator\src\supervisor\supervisor.js:97:12)
    at ProxyServer.emit (C:\Users\williams\AppData\Roaming\npm\node_modules\firebase-tools\node_modules\eventemitter3\index.js:144:27)
    at ClientRequest.proxyError (C:\Users\williams\AppData\Roaming\npm\node_modules\firebase-tools\node_modules\http-proxy\lib\http-proxy\passes\web-incoming.js:156:18)
    at emitOne (events.js:96:13)
    at ClientRequest.emit (events.js:191:7)
    at Socket.socketErrorListener (_http_client.js:358:9)
info: Execution took 60054 ms, finished with status: 'crash'
Error: Can't set headers after they are sent.
    at ServerResponse.setHeader (_http_outgoing.js:371:11)
    at ServerResponse.header (C:\Users\williams\AppData\Roaming\npm\node_modules\firebase-tools\node_modules\express\lib\response.js:730:10)
    at ServerResponse.send (C:\Users\williams\AppData\Roaming\npm\node_modules\firebase-tools\node_modules\express\lib\response.js:170:12)
    at ServerResponse.json (C:\Users\williams\AppData\Roaming\npm\node_modules\firebase-tools\node_modules\express\lib\response.js:256:15)
    at ProxyServer.Supervisor._proxy.on (C:\Users\williams\AppData\Roaming\npm\node_modules\firebase-tools\node_modules\@google-cloud\functions-emulator\src\supervisor\supervisor.js:97:12)
    at ProxyServer.emit (C:\Users\williams\AppData\Roaming\npm\node_modules\firebase-tools\node_modules\eventemitter3\index.js:144:27)
    at ClientRequest.proxyError (C:\Users\williams\AppData\Roaming\npm\node_modules\firebase-tools\node_modules\http-proxy\lib\http-proxy\passes\web-incoming.js:156:18)
    at emitOne (events.js:96:13)
    at ClientRequest.emit (events.js:191:7)
    at Socket.socketCloseListener (_http_client.js:334:9)

Code:

exports.getUsers = functions.https.onRequest((request, response) => {
  var x = [],
    similarityCount;

  db
    .ref("/users/" + request.query.userId)
    .once("value")
    .then(function(snapshot) {
      var jsonObject = snapshot.val();
      var basicProfileJsonObject = jsonObject.basicProfile;
      for (var key in basicProfileJsonObject) {
        if (utils.isNumber(basicProfileJsonObject[key])) {
          x.push(basicProfileJsonObject[key]);
        }
      }
      db.ref("/users/").once("value").then(function(snapshot) {
        var y = [];
        var jsonResponse = [];
        snapshot.forEach(function(item) {
          var user = item.val();
          let userId = user.basicProfile.userId;
          if (userId !== request.query.userId) {
            var basicProfileJsonObject = user.basicProfile;
            for (var key in basicProfileJsonObject) {
              if (utils.isNumber(basicProfileJsonObject[key])) {
                y.push(basicProfileJsonObject[key]);
              }
            }

            if (request.query.algo === "cosine") {
              // compute cosine value
              similarityCount = cosineUtils.cosineSimilarity(x, y);
            } else if (request.query.algo == "euclidean") {
              // compute euclidean distance value
              similarityCount = 1 / (1 + euclidean(x, y));
            } else if (request.query.algo === "pearson-correlation") {
              // compute pearson correlation coefficents
              similarityCount = pcorr.pearsonCorrelation(x, y);
            }
            console.log("------------------------------------");
            console.log(x);
            console.log("------------------------------------");
            console.log("------------------------------------");
            console.log(y);
            console.log("------------------------------------");
            console.log("------------------------------------");
            console.log(similarityCount);
            console.log("------------------------------------");
            jsonResponse.push(item.val());
            y = [];
          }
        });
        response.send(jsonResponse);
      });
    });
});

Can anyone help me what is going wrong ?

like image 836
N Sharma Avatar asked Aug 06 '17 14:08

N Sharma


People also ask

Can t send headers after they are sent?

The error "Error: Can't set headers after they are sent." means that you're already in the Body or Finished state, but some function tried to set a header or statusCode. When you see this error, try to look for anything that tries to send a header after some of the body has already been written.

Does firebase work on HTTP?

You can connect an HTTP function to Firebase Hosting. Requests on your Firebase Hosting site can be proxied to specific HTTP functions. This also allows you to use your own custom domain with an HTTP function.


1 Answers

This is definitely a tricky case. I think there's a complicated error case happening here and the error message is sub-par. Notice that there are two lines that say "Execution took 60022 ms, finished with status: X". My wild guess here is that the Cloud Function timed out (which then sends a response) but your code continued to run in the background. Eventually it tried to send the real response, but the response had already been sent and Express.js threw an exception.

As an aside, this Cloud Function is trying to load every single user in your application during the limit of an HTTP request. No matter how fast Cloud Functions or the Firebase Realtime Database gets, you're going to hit a limit if you try to fit a O(N) operation in a constant timeout. Is it possible to make your HTTP function calculate the similarity between two users? Or to proactively calculate and invalidate users' similarities in the background and return cached values in your HTTP function?

like image 56
Thomas Bouldin Avatar answered Sep 29 '22 11:09

Thomas Bouldin