Skip to content

Commit 2752f88

Browse files
authored
Sets the minimum number of Fly machines to 1 (#1535)
1 parent 2b47abd commit 2752f88

File tree

8 files changed

+157
-30
lines changed

8 files changed

+157
-30
lines changed

waspc/ChangeLog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ app todoApp {
1717
}
1818
```
1919

20+
### 🐞 Bug fixes / 🔧 small improvements
21+
- Changed the minimum number of machines that a server app is using when deployed to Fly.io from 0 to 1. This prevents the server app from shutting down when there are no requests to it. There might be some other work that the server is doing e.g. running periodic Jobs or sending e-mails, so we want to make sure that the server is always running.
22+
23+
2024
## 0.11.7
2125

2226
### 🐞 Bug fixes / 🔧 small improvements

waspc/packages/deploy/package-lock.json

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

waspc/packages/deploy/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"@typescript-eslint/eslint-plugin": "^5.48.0",
2121
"@typescript-eslint/parser": "^5.48.0",
2222
"eslint": "^8.31.0",
23+
"prettier": "^2.8.8",
2324
"typescript": "^4.9.4"
2425
}
2526
}

waspc/packages/deploy/src/providers/fly/helpers/helpers.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,16 @@ export function isYes(str: string): boolean {
99
}
1010

1111
export function ensureWaspDirLooksRight(thisCommand: Command): void {
12-
const dirContainsWasproot = fs.existsSync(path.join(thisCommand.opts().waspProjectDir, '.wasproot'));
12+
const dirContainsWasproot = fs.existsSync(
13+
path.join(thisCommand.opts().waspProjectDir, '.wasproot'),
14+
);
1315
if (dirContainsWasproot) {
1416
return;
1517
}
1618

17-
waspSays('The supplied Wasp directory does not appear to be a valid Wasp project.');
19+
waspSays(
20+
'The supplied Wasp directory does not appear to be a valid Wasp project.',
21+
);
1822
waspSays('Please double check your path.');
1923
exit(1);
2024
}
@@ -38,8 +42,11 @@ function getWaspBuildDir(waspProjectDir: string) {
3842
return path.join(waspProjectDir, '.wasp', 'build');
3943
}
4044

41-
export function ensureDirsInCmdAreAbsoluteAndPresent(thisCommand: Command): void {
42-
const waspProjectDirPath: string | undefined = thisCommand.opts().waspProjectDir;
45+
export function ensureDirsInCmdAreAbsoluteAndPresent(
46+
thisCommand: Command,
47+
): void {
48+
const waspProjectDirPath: string | undefined =
49+
thisCommand.opts().waspProjectDir;
4350
if (waspProjectDirPath) {
4451
if (!path.isAbsolute(waspProjectDirPath)) {
4552
waspSays('The Wasp dir path must be absolute.');
@@ -88,6 +95,10 @@ export function waspSays(str: string): void {
8895
console.log('🚀 \x1b[33m ' + str + ' \x1b[0m');
8996
}
9097

98+
export function boldText(str: string): string {
99+
return '\x1b[1m' + str + '\x1b[0m';
100+
}
101+
91102
export function displayWaspRocketImage(): void {
92103
// Escaping backslashes makes it look weird here, but it works in console.
93104
const asciiArt = `
@@ -109,7 +120,10 @@ export function getCommandHelp(command: Command): string {
109120
}
110121

111122
function trimUsage(usage: string): string {
112-
return usage.split(/[\r\n]+/)[0].replace('Usage: ', '').replace(' [options]', '');
123+
return usage
124+
.split(/[\r\n]+/)[0]
125+
.replace('Usage: ', '')
126+
.replace(' [options]', '');
113127
}
114128

115129
// There is a theoretical race condition here since we are modifying a global `$`
@@ -118,7 +132,9 @@ function trimUsage(usage: string): string {
118132
// times concurrently could change the setting incorrectly.
119133
// However, our pattern of awaiting for both `$` and `silence` calls without any random
120134
// callbacks using either means this interleaving should not ever happen.
121-
export async function silence(cmd: ($hh: Shell) => Promise<ProcessOutput>): Promise<ProcessOutput> {
135+
export async function silence(
136+
cmd: ($hh: Shell) => Promise<ProcessOutput>,
137+
): Promise<ProcessOutput> {
122138
const verboseSetting = $.verbose;
123139
$.verbose = false;
124140
const proc = await cmd($);

waspc/packages/deploy/src/providers/fly/helpers/tomlFileHelpers.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import path from 'node:path';
44
import { CommonOptions } from '../CommonOptions.js';
55

66
export interface TomlFilePaths {
7-
serverTomlPath: string;
8-
clientTomlPath: string;
7+
serverTomlPath: string;
8+
clientTomlPath: string;
99
}
1010

1111
export function getTomlFilePaths(options: CommonOptions): TomlFilePaths {
@@ -56,18 +56,30 @@ export function getAppNameFromToml(path: string): string {
5656
return data.app;
5757
}
5858

59-
export function getInferredBasenameFromServerToml(paths: TomlFilePaths): string {
59+
export function getInferredBasenameFromServerToml(
60+
paths: TomlFilePaths,
61+
): string {
6062
const serverName = getAppNameFromToml(paths.serverTomlPath);
6163
return serverName.replace('-server', '');
6264
}
6365

64-
export function getInferredBasenameFromClientToml(paths: TomlFilePaths): string {
66+
export function getInferredBasenameFromClientToml(
67+
paths: TomlFilePaths,
68+
): string {
6569
const clientName = getAppNameFromToml(paths.clientTomlPath);
6670
return clientName.replace('-client', '');
6771
}
6872

69-
export function replaceLineInLocalToml(searchValue: string | RegExp, replaceValue: string): void {
73+
export function replaceLineInLocalToml(
74+
searchValue: string | RegExp,
75+
replaceValue: string,
76+
): void {
7077
const content = fs.readFileSync('fly.toml', 'utf8');
7178
const updatedContent = content.replace(searchValue, replaceValue);
7279
fs.writeFileSync('fly.toml', updatedContent);
7380
}
81+
82+
export function doesLocalTomlContainLine(searchValue: string | RegExp): boolean {
83+
const content = fs.readFileSync('fly.toml', 'utf8');
84+
return content.search(searchValue) !== -1;
85+
}

waspc/packages/deploy/src/providers/fly/setup/setup.ts

Lines changed: 80 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,32 @@
1-
import { $, cd } from 'zx';
1+
import { $, cd, question } from 'zx';
22
import crypto from 'crypto';
33
import {
44
clientTomlExistsInProject,
55
copyLocalClientTomlToProject,
66
copyLocalServerTomlToProject,
77
deleteLocalToml,
8+
doesLocalTomlContainLine,
89
getTomlFilePaths,
910
replaceLineInLocalToml,
1011
serverTomlExistsInProject,
1112
} from '../helpers/tomlFileHelpers.js';
1213
import { createDeploymentInfo, DeploymentInfo } from '../DeploymentInfo.js';
1314
import { SetupOptions } from './SetupOptions.js';
14-
import { cdToClientBuildDir, cdToServerBuildDir, makeIdempotent, getCommandHelp, waspSays } from '../helpers/helpers.js';
15+
import {
16+
cdToClientBuildDir,
17+
cdToServerBuildDir,
18+
makeIdempotent,
19+
getCommandHelp,
20+
waspSays,
21+
boldText,
22+
} from '../helpers/helpers.js';
1523
import { createFlyDbCommand } from '../index.js';
1624

17-
export async function setup(baseName: string, region: string, options: SetupOptions): Promise<void> {
25+
export async function setup(
26+
baseName: string,
27+
region: string,
28+
options: SetupOptions,
29+
): Promise<void> {
1830
waspSays('Setting up your Wasp app with Fly.io!');
1931

2032
const buildWasp = makeIdempotent(async () => {
@@ -24,7 +36,12 @@ export async function setup(baseName: string, region: string, options: SetupOpti
2436
});
2537

2638
const tomlFilePaths = getTomlFilePaths(options);
27-
const deploymentInfo = createDeploymentInfo(baseName, region, options, tomlFilePaths);
39+
const deploymentInfo = createDeploymentInfo(
40+
baseName,
41+
region,
42+
options,
43+
tomlFilePaths,
44+
);
2845

2946
if (serverTomlExistsInProject(tomlFilePaths)) {
3047
waspSays(`${tomlFilePaths.serverTomlPath} exists. Skipping server setup.`);
@@ -40,7 +57,11 @@ export async function setup(baseName: string, region: string, options: SetupOpti
4057
await setupClient(deploymentInfo);
4158
}
4259

43-
waspSays(`Don't forget to create your database by running "${getCommandHelp(createFlyDbCommand)}".`);
60+
waspSays(
61+
`Don't forget to create your database by running "${getCommandHelp(
62+
createFlyDbCommand,
63+
)}".`,
64+
);
4465
}
4566

4667
async function setupServer(deploymentInfo: DeploymentInfo<SetupOptions>) {
@@ -50,8 +71,10 @@ async function setupServer(deploymentInfo: DeploymentInfo<SetupOptions>) {
5071
deleteLocalToml();
5172

5273
const launchArgs = [
53-
'--name', deploymentInfo.serverName,
54-
'--region', deploymentInfo.region,
74+
'--name',
75+
deploymentInfo.serverName,
76+
'--region',
77+
deploymentInfo.region,
5578
];
5679

5780
if (deploymentInfo.options.org) {
@@ -61,6 +84,31 @@ async function setupServer(deploymentInfo: DeploymentInfo<SetupOptions>) {
6184
// This creates the fly.toml file, but does not attempt to deploy.
6285
await $`flyctl launch --no-deploy ${launchArgs}`;
6386

87+
const minMachinesOptionRegex = /min_machines_running = 0/g;
88+
89+
if (!doesLocalTomlContainLine(minMachinesOptionRegex)) {
90+
await question(`\n⚠️ There was a possible issue setting up your server app.
91+
We tried modifying your server fly.toml to set ${boldText(
92+
'min_machines_running = 1',
93+
)}, but couldn't find the option ${boldText(
94+
'min_machines_running',
95+
)} in the fly.toml.
96+
97+
We advise that you additionaly check what is the value for "minimal number of machines running" on Fly
98+
for this server app and confirm that it is set to the value you are OK with.
99+
100+
Be aware that if it is set to 0, your server will shut down when there are no requests from the client,
101+
which might be an issue for you if you have recurring Jobs or some other processes that need to keep
102+
running on the server even without external input, in which case we advise keeping "minimal number
103+
of machines running" setting at a number larger than zero.
104+
105+
Contact the Wasp Team at our Discord server if you need help with this: https://discord.gg/rzdnErX
106+
107+
Press any key to continue or Ctrl+C to cancel.`);
108+
} else {
109+
replaceLineInLocalToml(minMachinesOptionRegex, 'min_machines_running = 1');
110+
}
111+
64112
copyLocalServerTomlToProject(deploymentInfo.tomlFilePaths);
65113

66114
const randomString = crypto.randomBytes(32).toString('hex');
@@ -74,7 +122,7 @@ async function setupServer(deploymentInfo: DeploymentInfo<SetupOptions>) {
74122
];
75123

76124
if (deploymentInfo.options.serverSecret.length > 0) {
77-
deploymentInfo.options.serverSecret.forEach(secret => {
125+
deploymentInfo.options.serverSecret.forEach((secret) => {
78126
secretsArgs.push(secret);
79127
});
80128
}
@@ -92,8 +140,10 @@ async function setupClient(deploymentInfo: DeploymentInfo<SetupOptions>) {
92140
deleteLocalToml();
93141

94142
const launchArgs = [
95-
'--name', deploymentInfo.clientName,
96-
'--region', deploymentInfo.region,
143+
'--name',
144+
deploymentInfo.clientName,
145+
'--region',
146+
deploymentInfo.region,
97147
];
98148

99149
if (deploymentInfo.options.org) {
@@ -103,9 +153,26 @@ async function setupClient(deploymentInfo: DeploymentInfo<SetupOptions>) {
103153
// This creates the fly.toml file, but does not attempt to deploy.
104154
await $`flyctl launch --no-deploy ${launchArgs}`;
105155

106-
// goStatic listens on port 8043 by default, but the default fly.toml
107-
// assumes port 8080 (or 3000, depending on flyctl version).
108-
replaceLineInLocalToml(/internal_port = \d+/g, 'internal_port = 8043');
156+
const internalPortOptionRegex = /internal_port = \d+/g;
157+
158+
if (!doesLocalTomlContainLine(internalPortOptionRegex)) {
159+
await question(`\n⚠️ There was an issue setting up your client app.
160+
We tried modifying your client fly.toml to set ${boldText(
161+
'internal_port = 8043',
162+
)}, but couldn't find the option ${boldText(
163+
'internal_port',
164+
)} in the fly.toml.
165+
166+
This means your client app might not be accessible.
167+
168+
Contact the Wasp Team at our Discord server if you need help with this: https://discord.gg/rzdnErX
169+
170+
Press any key to continue or Ctrl+C to cancel.`);
171+
} else {
172+
// goStatic listens on port 8043 by default, but the default fly.toml
173+
// assumes port 8080 (or 3000, depending on flyctl version).
174+
replaceLineInLocalToml(internalPortOptionRegex, 'internal_port = 8043');
175+
}
109176

110177
copyLocalClientTomlToProject(deploymentInfo.tomlFilePaths);
111178

waspc/waspc.cabal

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ data-files:
6565
packages/studio/dist/**/*.js
6666
packages/studio/dist/**/*.html
6767
packages/studio/dist/**/*.css
68-
packages/studio/dist/**/*.png
6968
packages/studio/package.json
7069
packages/studio/package-lock.json
7170
data-dir: data/

web/docs/advanced/deployment/cli.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,23 @@ wasp deploy fly create-db mia
4747
wasp deploy fly deploy
4848
```
4949

50-
The commands above use the app basename `my-wasp-app` and deploy it to the _Miami, Florida (US) region_ (called `mia`).
50+
The commands above use the app basename `my-wasp-app` and deploy it to the _Miami, Florida (US) region_ (called `mia`). Read more about Fly.io regions [here](#flyio-regions).
51+
52+
:::caution Unique Name
53+
Your app name must be unique across all of Fly or deployment will fail.
54+
:::
5155

5256
The basename is used to create all three app tiers, resulting in three separate apps in your Fly dashboard:
5357

5458
- `my-wasp-app-client`
5559
- `my-wasp-app-server`
5660
- `my-wasp-app-db`
5761

58-
:::caution Unique Name
59-
Your app name must be unique across all of Fly or deployment will fail.
60-
:::
62+
You'll notice that Wasp creates two new files in your project root directory:
63+
- `fly-server.toml`
64+
- `fly-client.toml`
6165

62-
Read more about Fly.io regions [here](#flyio-regions).
66+
You should include these files in your version control so that you can deploy your app with a single command in the future.
6367

6468
### Using a Custom Domain For Your App
6569

@@ -159,6 +163,8 @@ It accepts the following arguments:
159163
After running `setup`, Wasp creates two new files in your project root directory: `fly-server.toml` and `fly-client.toml`.
160164
You should include these files in your version control.
161165

166+
You **can edit the `fly-server.toml` and `fly-client.toml` files** to further configure your Fly deployments. Wasp will use the TOML files when you run `deploy`.
167+
162168
If you want to maintain multiple apps, you can add the `--fly-toml-dir <abs-path>` option to point to different directories, like "dev" or "staging".
163169

164170
:::caution Execute Only Once

0 commit comments

Comments
 (0)