Skip to content

Functions and "onDisconnect", best practices? #176

@feildmaster

Description

@feildmaster

So I seem to be having a unique issue that no one really expects to run into in cloud functions. reference.onDisconnect has a very sporadic handling in cloud functions, it either works when an error is thrown, or doesn't work until the process decides to randomly exit (maybe?). I don't know. I haven't waited around long enough to find out when it would finally trigger the disconnect.

I suppose I should begin with showing my use case, which is an asynchronous external response handler (wow that's a mouthful).

module.exports = functions.https.onRequest((req, res) => {
  // Start off by reading from the database, telling 
  return root.child(`responses`).once('value').then((value) => {
    // do some value magic, in my case I look for "listeners".
    const listeners = value.val();
    const dataRef = root.child('data');
    dataRef.onDisconnect().remove(); // I want this to be removed on disconnect
    // I then apply the key to the listeners
    listeners.forEach((id) => {
      const key = value.ref.child(`keys/${dataRef.key}`);
      key.onDisconnect().remove();
      key.set(true);
    });
    return dataRef;
  })
  .then((dataRef) => new Promise(() => {
    // By this point I now have at least 2 references waiting to be deleted on disconnect
    // and I want to do some async things
    const waitOnThis = dataRef.child('status');
    // Timeout after 5 seconds, for if something is misconfigured
    setTimeout(() => {exit(504), 5000});
    // Listen for data
    hookStatus.on('value', (snapshot) => {
      if (snapshot.val() === null) return;
      hookStatus.off('value'); // Stop listening so the process can end, I hoped
      exit(snapshot.val());
    });
    function exit(code) {
      res.send(code);
      resolve();
    }
  }))
  // This is the wacky part, Now I either have to go offline/online or do process.exit()
  // in order to trigger the ref.onDisconnect()'s, without throwing an error to exit the process.
  .then(() => {
    // Go offline/online, possibly keep process for later use?
    admin.database().goOffline();
    admin.database().goOnline();
    // Or exit() and possibly have firebase complain about it for some reason
    process.exit();
  });
});

For a working version, please refer to webhooks.js.

I guess what I'm really positing here is:
What is the best way to handle this situation?
What are the repercussions of process.exit()?
Why does the process (potentially) stick around? Does it get reused?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions