Skip to content

Commit 82629ef

Browse files
authored
Fly deployment (#29)
1 parent baf1f8d commit 82629ef

File tree

10 files changed

+79
-11
lines changed

10 files changed

+79
-11
lines changed

.dockerignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
**/node_modules
2+
**/.env
3+
**/wasp-analytics-cached-events.json
4+
**/dist
5+
.husky/_/**/*
6+
fly.toml

.github/workflows/fly-deploy.yml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: Fly Deploy
2+
on:
3+
push:
4+
branches:
5+
- production
6+
jobs:
7+
deploy:
8+
name: Deploy app
9+
runs-on: ubuntu-latest
10+
concurrency: deploy-group
11+
steps:
12+
- uses: actions/checkout@v4
13+
- uses: superfly/flyctl-actions/setup-flyctl@master
14+
- run: flyctl deploy --remote-only
15+
env:
16+
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ node_modules/
22
.env
33
wasp-analytics-cached-events.json
44
dist/
5+
.DS_STORE

Dockerfile

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
FROM node:20-slim AS builder
2+
3+
WORKDIR /app
4+
5+
# Copy package files
6+
COPY package*.json ./
7+
8+
# Install dependencies
9+
RUN npm ci
10+
11+
# Copy source code
12+
COPY . .
13+
14+
# Build the application
15+
RUN npm run build
16+
17+
# Set environment variables
18+
ENV NODE_ENV=production
19+
20+
# Create a non-root user and switch to it
21+
RUN addgroup --system --gid 1001 nodejs \
22+
&& adduser --system --uid 1001 discordbot \
23+
&& chown -R discordbot:nodejs /app
24+
25+
USER discordbot
26+
27+
CMD ["npm", "run", "start"]

Procfile

-1
This file was deleted.

README.md

+6-3
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@ Run `npm run buildAndCalcAnalytics` to run analytics manually and get the report
2727

2828
### Deployment
2929

30-
Deployed instance of server is running on Heroku. Whatever you push to `production` branch automatically gets re-deployed to Heroku.
30+
The bot is deployed to [Fly](https://fly.io/). The `fly.toml` file contains the configuration for the deployment. The Fly deployoment uses the `Dockerfile` to build the image.
3131

32-
Heroku cares about `Procfile` that we have in the root of the project, and will run the command there to start the project once deployed.
32+
The bot is deployed automatically on every push to the `production` branch. You can also deploy with the Fly CLI by running `fly deploy`.
3333

34-
Heroku knows it is a node project, so it will run `npm install` when deploying it, which will also run `npm run postinstall`, which is why it all works, because `npm run postinstall` does building (of TS).
34+
The Fly.io server on which wasp-bot is deployed has a persistent volume attached to it called `wasp_bot_storage` mounted at `/data` dir, in order to persist the cached analytics events from Posthog between deployments.
35+
Our Wasp-bot app provides the `WASP_ANALYTICS_CACHED_EVENTS_JSON_PATH` environment variable, which in this case we set to point to `/data/wasp-analytics-cached-events.json`.
36+
37+
You can check production app logs with `fly logs` and SSH into the app container with `fly ssh console`.

env.example

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
WASP_POSTHOG_KEY=
22
DISCORD_BOT_TOKEN=
3+

fly.toml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# fly.toml app configuration file generated for wasp-bot on 2024-12-21T10:28:44+01:00
2+
#
3+
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
4+
#
5+
6+
app = 'wasp-bot'
7+
primary_region = 'fra'
8+
9+
[mounts]
10+
destination = "/data"
11+
source = "wasp_bot_storage"
12+
13+
[[vm]]
14+
cpu_kind = 'shared'
15+
cpus = 1
16+
memory = '1gb'

package.json

-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
"startBot": "node ./dist/bot.js",
1111
"calcAnalytics": "node ./dist/analytics/cli.js",
1212
"build": "tsc",
13-
"postinstall": "COMMENT: We do building in this step because that way Heroku will run it at the right moment when deploying.",
14-
"postinstall": "npm run build",
1513
"prepare": "husky install",
1614
"format": "prettier . --write",
1715
"lint": "eslint ."

src/analytics/events.ts

+6-5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ const POSTHOG_PROJECT_API_KEY = "CdDd2A0jKTI2vFAsrI9JWm3MqpOcgHz1bMyogAcwsE4";
1111

1212
const OLDEST_EVENT_TIMESTAMP = "2021-01-22T19:42:56.684632+00:00";
1313

14+
const CACHE_FILE_PATH =
15+
process.env.WASP_ANALYTICS_CACHED_EVENTS_JSON_PATH ??
16+
"./wasp-analytics-cached-events.json";
17+
1418
export interface PosthogEvent {
1519
distinct_id: string;
1620
timestamp: Date;
@@ -137,17 +141,14 @@ async function fetchEvents({
137141
};
138142
}
139143

140-
// NOTE: This file is gitignored. If you change its name, update it also in gitignore.
141-
const cachedEventsFilePath = "wasp-analytics-cached-events.json";
142-
143144
// Returns: [PosthogEvent]
144145
// where events are guaranteed to be continuous, with no missing events between the cached events.
145146
// Newest event is first (index 0), and oldest event is last, and cached events are continuous,
146147
// in the sense that there is no events between the oldest and newest that is missing.
147148
// There might be missing events before or after though.
148149
async function loadCachedEvents(): Promise<PosthogEvent[]> {
149150
try {
150-
return JSON.parse(await fs.readFile(cachedEventsFilePath, "utf-8"));
151+
return JSON.parse(await fs.readFile(CACHE_FILE_PATH, "utf-8"));
151152
} catch (e) {
152153
if (e.code === "ENOENT") return [];
153154
throw e;
@@ -156,7 +157,7 @@ async function loadCachedEvents(): Promise<PosthogEvent[]> {
156157

157158
// Expects events that follow the same rules as the ones returned by `loadCachedEvents()`.
158159
async function saveCachedEvents(events: PosthogEvent[]): Promise<void> {
159-
await fs.writeFile(cachedEventsFilePath, JSON.stringify(events), "utf-8");
160+
await fs.writeFile(CACHE_FILE_PATH, JSON.stringify(events), "utf-8");
160161
}
161162

162163
function getOldestEventTimestampOrNull(events: PosthogEvent[]): Date {

0 commit comments

Comments
 (0)