Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firebase app never terminates, even after deleteApp() #5692

Closed
lcrocker opened this issue Nov 2, 2021 · 4 comments · Fixed by #5701
Closed

Firebase app never terminates, even after deleteApp() #5692

lcrocker opened this issue Nov 2, 2021 · 4 comments · Fixed by #5701

Comments

@lcrocker
Copy link

lcrocker commented Nov 2, 2021

[REQUIRED] Describe your environment

Ubuntu 20.04 LTS, kernel 5.11.0-38-generic
NodeJS 14.16.0
Firebase 9.2.0
TypeScript 4.4.4

[REQUIRED] Describe the problem

App never terminates. Regardless of whether deleteApp() is called or not, node is left waiting for something and hangs.
This may be the a duplicate of #4987 , which is closed and locked so I can't add this as a comment there.

Relevant Code:

import { CloudFunctionsServiceClient } from "@google-cloud/functions";
import { initializeApp, deleteApp } from "firebase/app";
import { getFunctions, httpsCallable } from "firebase/functions";

import minimist from "minimist";
import fs from "fs";

import { JsonMap } from "./functions/src/generic/lib";

function delay(ms: number): Promise<void> {
        return new Promise((resolve) => {
                setTimeout(() => { resolve(); }, ms);
        });
}

class App {
        private client = new CloudFunctionsServiceClient();
        private fbApp = initializeApp({
                projectId: "xxxx-xxxx",
                apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
                authDomain: "xxxx-xxxx.firebaseapp.com",
                databaseURL: "https://xxxx-xxxx-default-rtdb.firebaseio.com",
                storageBucket: "xxxx-xxxx.appspot.com",
                messagingSenderId: "xxxxxxxxxxxx",
                appId: "1:xxxxxxxxxxxx:web:xxxxxxxxxxxxxxxxxxxxxx",
        });
        private functions = getFunctions(this.fbApp);

        private deviceId = "";
        private app: JsonMap = {};
        private verbose = false;
        private command = "";
        private filenames: string[] = [];

        constructor() {
                const argv = minimist(process.argv.slice(2), {
                        boolean: [ "v" ],
                        string: [ "d", "c", "_" ],
                });
                if (argv["v"]) this.verbose = true;
                if (argv["c"]) this.command = argv["c"];
                if (argv["d"]) this.deviceId = argv["d"];
                this.filenames = argv["_"];

                if (0 === this.filenames.length && "" === this.command) {
                        throw new Error("No operation specified");
                }
                if (! this.deviceId) {
                        throw new Error("No deviceId specified");
                }
                if (! (this.deviceId.startsWith("d"))) this.deviceId = "d" + this.deviceId;
        }

        async getConfig(): Promise<void> {
                const cfgText = await fs.promises.readFile("functions/.runtimeconfig.json");
                const cfg = JSON.parse(cfgText.toString());
                // console.log(cfg);
                if (! (cfg && "app" in cfg && "name" in cfg.app)) {
                        throw new Error("Inadequate local config");
                }
                this.app = cfg.app;
        }

        async run(): Promise<void> {
                await this.getConfig();
                /*
                const [functions] = await this.client.listFunctions({
                        parent: `projects/${this.app.name}/locations/-`,
                });
                for (var f of functions) {
                        console.info(f.name);
                }
                */
                const sendCmd = httpsCallable(this.functions, "sendDeviceCommand2");

                if (this.command) {
                        let result = await sendCmd({
                                deviceId: this.deviceId,
                                do: [ this.command ],
                        });
                        console.info(result);
                }
                for (const f of this.filenames) {
                        const buf = await fs.promises.readFile(f);
                        const lines = buf.toString().split("\n");

                        for (const line of lines) {
                                const lt = line.trim();
                                if ("" === lt) continue;
                                await delay(2000);

                                let result = await sendCmd({
                                        deviceId: this.deviceId,
                                        do: [ lt ],
                                });
                        }
                }
                await deleteApp(this.fbApp);
                // process.exit(0);
        }
}

(new App()).run().catch((e) => { console.error(e); });
@google-oss-bot
Copy link
Contributor

I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.

@lcrocker
Copy link
Author

lcrocker commented Nov 2, 2021

"wtfnode" shows that a timer is still running (it's from a "failAfter()" call):

  • Timers:
    • (70000 ~ 1 min) (anonymous) @ /home/lee/work/cld_backend_all/zled-5090/node_modules/@firebase/functions/dist/index.node.cjs.js:458

I can only find one call, In packages/functions/src/service.ts, line 252. It's in a Promise.race() with the actual call, which completes pretty quickly, so the minute-plus timeout is left running (it does eventually timeout and allow the program to exit--I'd never waited that long until I found the code).

The code that responds to success should cancel this timer.

@schmidt-sebastian
Copy link
Contributor

This would also explain #5628

@Feiyang1 Can you take a look?

@hsubox76
Copy link
Contributor

hsubox76 commented Nov 8, 2021

Looks like a bug. Canceling that timeout should be handled in the functions service _delete method. I'll look into adding that.

@hsubox76 hsubox76 self-assigned this Nov 8, 2021
@firebase firebase locked and limited conversation to collaborators Dec 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants