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

Catch OSX port 5000 in-use #4415

Merged
merged 6 commits into from
Apr 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
- Fix URL with wrong host returned in storage resumable upload (#4374).
- Fixes Firestore emulator transaction expiration and reused bug.
- Fixes Firestore emulator deadlock bug. [#2452](https://github.com/firebase/firebase-tools/issues/2452)
- Ensure that the hosting emulator port is not claimed by OSX (#4415).
- Improves support for prerelease versions in `ext:dev:publish` (#4244).
- Fixes console error on large uploads to Storage Emulator (#4407).
- Fixes cross-platform incompatibility with Storage Emulator exports (#4411).
42 changes: 30 additions & 12 deletions src/serve/hosting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Writable } from "stream";
import { EmulatorLogger } from "../emulator/emulatorLogger";
import { Emulators } from "../emulator/types";
import { createDestroyer } from "../utils";
import { execSync } from "child_process";

const MAX_PORT_ATTEMPTS = 10;
let attempts = 0;
Expand Down Expand Up @@ -44,6 +45,34 @@ function startServer(options: any, config: any, port: number, init: TemplateServ
stream: morganStream,
});

const portInUse = () => {
const message = "Port " + options.port + " is not available.";
logger.log("WARN", clc.yellow("hosting: ") + message + " Trying another port...");
if (attempts < MAX_PORT_ATTEMPTS) {
// Another project that's running takes up to 4 ports: 1 hosting port and 3 functions ports
attempts++;
startServer(options, config, port + 5, init);
} else {
logger.log("WARN", message);
throw new FirebaseError("Could not find an open port for hosting development server.", {
exit: 1,
});
}
};

// On OSX, some ports may be reserved by the OS in a way that node http doesn't detect.
// Starting in MacOS 12.3 it does this with port 5000 our default port. This is a bad
// enough devexp that we should special case and ensure it's available.
if (process.platform === "darwin") {
try {
execSync(`lsof -i :${port}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking through this, it seems like this only checks if the initial port is being used by osX, and will still break out if a subsequent attempt hits a osx occupied port. Should we include this if (platform == 'darwin') lsof in portInUse() as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

portInUse recurses, so it should work in subsequent attempts

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see line 54

portInUse();
return;
} catch (e) {
// if lsof errored the port is NOT in use, continue
}
}

const server = superstatic({
debug: false,
port: port,
Expand Down Expand Up @@ -85,18 +114,7 @@ function startServer(options: any, config: any, port: number, init: TemplateServ
// eslint-disable-next-line @typescript-eslint/no-explicit-any
server.on("error", (err: any) => {
if (err.code === "EADDRINUSE") {
const message = "Port " + options.port + " is not available.";
logger.log("WARN", clc.yellow("hosting: ") + message + " Trying another port...");
if (attempts < MAX_PORT_ATTEMPTS) {
// Another project that's running takes up to 4 ports: 1 hosting port and 3 functions ports
attempts++;
startServer(options, config, port + 5, init);
} else {
logger.log("WARN", message);
throw new FirebaseError("Could not find an open port for hosting development server.", {
exit: 1,
});
}
portInUse();
} else {
throw new FirebaseError(
"An error occurred while starting the hosting development server:\n\n" + err.toString(),
Expand Down