Cloud Function experiences a timeout error when attempting to subscribe an FCM token to a topic within the HTTP function

Example Code:

Main.ts:

import * as admin from "firebase-admin"
import fetch, { Headers } from "node-fetch";

interface FooPayload {
  topic: string,
  token: string,
}

exports.foo = functions.https.onCall(async (data, context) => {
  if (data != null) {
    const payload: FooPayload = {
      topic: data.topic,
      token: data.token,
    }

    const url = `https://${location}-${project}.cloudfunctions.net/subscribeToTopic`
    await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        topic: payload.topic,
        token: payload.token,
      }),
    })
  }
  return null;
});

export const subscribeToTopic = functions.https.onRequest(async (req, res) => {
  const payload = req.body as FooPayload;
  fetch('https://iid.googleapis.com/iid/v1/' + payload.token + '/rel/topics/' + payload.topic, {
    method: 'POST',
    headers: new Headers({
      'Authorization': 'key=AA...Wp9',
      'Content-Type': 'application/json'
    })
  }).then(response => {
    if (response.status < 200 || response.status >= 400) {
      res.sendStatus(299)
    }
  }).catch(error => {
    console.error(error);
    res.sendStatus(299)
  })
  return Promise.resolve();
})

When running foo in my app, I encountered a timeout error in the logs:

textPayload: "Function execution took 60051 ms. Finished with status: timeout"


However, switching subscribeToTopic from an HTTP function to a callable function resolves the issue:

exports.subscribeToTopic = functions.https.onCall(async (data, context) => {
  fetch('https://iid.googleapis.com/iid/v1/' + data.token + '/rel/topics/' + data.topic, {
    method: 'POST',
    headers: new Headers({
      'Authorization': 'key=AA...Wp9',
      'Content-Type': 'application/json'
    })
  }).then(response => {
    if (response.status < 200 || response.status >= 400) {
      console.log('Error = ' + response.error);
    }
  }).catch(error => {
    console.error(error);
  })
  return null;
});

(I may be overlooking a simple error as a TypeScript beginner. Any guidance would be greatly appreciated :)

Answer №1

Avoid using return Promise.resolve(); in HTTPS Cloud Functions:

  1. HTTPS Cloud Functions should be terminated with send(), redirect(), or end();
  2. return Promise.resolve(); gets executed before the asynchronous call to fetch is complete.

Consider the following implementation (not tested):

export const subscribeToTopic = functions.https.onRequest(async (req, res) => {
    
    try {
        const payload = req.body as BarPayload;
        const response = await fetch('https://iid.googleapis.com/iid/v1/' + payload.token + '/rel/topics/' + payload.topic, {
            method: 'POST',
            headers: new Headers({
                'Authorization': 'key=AA...Wp9',
                'Content-Type': 'application/json'
            })
        });
    
        if(response.status < 200 || response.status >= 400) {
            res.status(299).send();
        }
    } catch (error) {
        res.status(400).send();
    }
    
  })

Questioning the separation of business logic in two Cloud Functions. Why not directly fetch https://iid.googleapis.com within the bar Callable Cloud Function?

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing MakeStyles from Material UI to add styling to a nested element

I was pondering the possibility of applying a style specifically to a child element using MakesStyles. For instance, in a typical HTML/CSS project: <div className="parent"> <h1>Title!</h1> </div> .parent h1 { color: # ...

Encountering a TypeError while trying to run Pythonshell on my Mac device

When I run a python script in node.js using python shell, it works perfectly on my Windows system. However, I encounter an error when trying to run the same thing on my Macbook: Error: TypeError: can't multiply sequence by non-int of type 'float ...

The presence of v-if does not depend on the model value to toggle the element

I have a scenario where I want to hide the dropdown menu for US states if a different country other than the US is selected. The code snippet I am using to achieve this functionality is shown below: <b-row v-for="demo in demographics" :key=&qu ...

Is there a way for me to update the placeholder text in my script from "CHANGE ME

Can anyone help me troubleshoot this code that's not working on my computer? I have a paragraph with the text CHANGE ME inside an element with the id "warning". I want to update this text when the login button is clicked, but it doesn't seem to ...

Encountering a blank webpage displaying a warning that reads, "The use of 'event.returnValue' is outdated

Although this issue has been discussed before and was previously considered a bug, I am currently using jQuery v1.11.0, which should have resolved it. The problem I am encountering is that when my page loads, there is supposed to be a slide-in effect (as a ...

Exploring the main directive flow, attaining access to `ctrl.$modelView` in AngularJS is

Four Methods Explained: What Works and What Doesn't I recently created an angular js directive where I encountered difficulty accessing the ctrl.$modelValue in the main flow. In my quest to find a solution, I came up with four potential methods, eac ...

Angular directive that verifies the presence of a specific number of child li elements

Currently, I have a basic ul that utilizes ng-repeats to display li elements fetched from an external source via a promise. There is also a search input present which filters these elements, and I want the ul to be hidden when there are no more elements th ...

Tips for using tooltip.format() to access an array of objects in anychart.js

Having difficulty displaying an array of objects in the tooltip of an Anychart.js map. I know we can access the dataset using %[name of property in data set]. The structure of my dataset is as follows: { "country": "Austria", &q ...

Aggregate array based on specified criteria in ReactJS

Let's consider the following array data: array = [ { id: 1, count: 0.5 cost: 100 user: {id: 1, name: "John 1"}, type: {id: 1, name: "T1"}, period: {id: 1, name: "2021"} ...

Automatically select a value in MUI AutoComplete and retrieve the corresponding object

I recently set up a list using the MUI (v4) Select component. I've received a feature request to make this list searchable due to its extensive length. Unfortunately, it appears that the only option within MUI library for this functionality is the Au ...

Exploring the integration of methods in Vue.js components

Within my Vuejs project, I developed a new form component and integrated it into the main index component. This new component needs to validate certain fields, with validation methods already created in the parent component. However, I am facing difficulti ...

Exporting SVG to image in Ionic is successful on Android devices, but the image gets cut off when viewed on

I am facing an issue with exporting an SVG as a base64 encoded image and sending it to the server for storage on Google Cloud Storage. The process works fine on Android and in browsers, but fails when attempted on a physical device running IOS. On IOS, t ...

Accessing Firebase with .NET C# for data retrieval

I am encountering issues when trying to retrieve data to my .net application from a Firebase-hosted database. During the debugging process, I observed that the response contains [{"Description":"desccc","Id":2},{"Description":"asdfasdf","Id":1}], which is ...

Guide to forming an array by extracting specific properties from a nested JSON array using javascript

Currently, I have this list: list = { id: 1, arr: [ {index : 1 , description: "lol" , author: "Arthur"}, {index : 2 , description: "sdadsa" , author: "Bob"}, {index : 3 , desc ...

Struggling to interpret the array of objects retrieved from a call to UrlFetchApp.fetch in Google App Script

When UrlFetchApp.fetch is called, it provides an array of objects that are stored in the variable 'results': var results = [{"Category 1": "Benefits/Compensatio", "Category 2": "Compensation", "Category 3": "Recognizing You", "Processing Team": ...

The implementation of a universal translation system in Express JS

I have developed a straightforward translation module for Express JS. It exists as a global object in the application scope and is initialized during application runtime: translator.configure({ translations: 'translations.json' }); I have i ...

Sorting elements in order based on their attribute values using jQuery

Exploring the use of the data attribute with jQuery for the first time, I am attempting to reorder an element based on its data-order attribute. I am struggling to retrieve the correct value of the data-order attribute as it keeps returning 'undefine ...

Struggling to construct a binary tree as my descendants are not arranged in the right sequence

I am currently working on building a binary tree using PHP, MySQL, and a jQuery plugin developed by Frank-Mich. Here is the progress I have made so far... DATABASE STRUCTURE CREATE TABLE IF NOT EXISTS `members` ( `id` int(11) NOT NULL AUTO_INCREMENT, ...

Javascript Solution for Testing Palindromes in a Linked List

I recently researched the solution for a palindrome problem using Javascript. There is one particular line of code that I am struggling to comprehend, and I'm hoping someone can shed some light on it for me. Here is the code snippet in question: thi ...

Exploring the nuances of developing React components

I've noticed that there are two common ways of creating a component import React from 'react'; class Alpha extends React.Component { render(){ ... } } or import React, { Component } from 'react'; class Alpha extends Com ...