Skip to content

Commit

Permalink
Fly deployment (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
infomiho authored Jan 8, 2025
1 parent baf1f8d commit 82629ef
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 11 deletions.
6 changes: 6 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
**/node_modules
**/.env
**/wasp-analytics-cached-events.json
**/dist
.husky/_/**/*
fly.toml
16 changes: 16 additions & 0 deletions .github/workflows/fly-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Fly Deploy
on:
push:
branches:
- production
jobs:
deploy:
name: Deploy app
runs-on: ubuntu-latest
concurrency: deploy-group
steps:
- uses: actions/checkout@v4
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: flyctl deploy --remote-only
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ node_modules/
.env
wasp-analytics-cached-events.json
dist/
.DS_STORE
27 changes: 27 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM node:20-slim AS builder

WORKDIR /app

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm ci

# Copy source code
COPY . .

# Build the application
RUN npm run build

# Set environment variables
ENV NODE_ENV=production

# Create a non-root user and switch to it
RUN addgroup --system --gid 1001 nodejs \
&& adduser --system --uid 1001 discordbot \
&& chown -R discordbot:nodejs /app

USER discordbot

CMD ["npm", "run", "start"]
1 change: 0 additions & 1 deletion Procfile

This file was deleted.

9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ Run `npm run buildAndCalcAnalytics` to run analytics manually and get the report

### Deployment

Deployed instance of server is running on Heroku. Whatever you push to `production` branch automatically gets re-deployed to Heroku.
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.

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.
The bot is deployed automatically on every push to the `production` branch. You can also deploy with the Fly CLI by running `fly deploy`.

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).
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.
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`.

You can check production app logs with `fly logs` and SSH into the app container with `fly ssh console`.
1 change: 1 addition & 0 deletions env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
WASP_POSTHOG_KEY=
DISCORD_BOT_TOKEN=

16 changes: 16 additions & 0 deletions fly.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# fly.toml app configuration file generated for wasp-bot on 2024-12-21T10:28:44+01:00
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#

app = 'wasp-bot'
primary_region = 'fra'

[mounts]
destination = "/data"
source = "wasp_bot_storage"

[[vm]]
cpu_kind = 'shared'
cpus = 1
memory = '1gb'
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
"startBot": "node ./dist/bot.js",
"calcAnalytics": "node ./dist/analytics/cli.js",
"build": "tsc",
"postinstall": "COMMENT: We do building in this step because that way Heroku will run it at the right moment when deploying.",
"postinstall": "npm run build",
"prepare": "husky install",
"format": "prettier . --write",
"lint": "eslint ."
Expand Down
11 changes: 6 additions & 5 deletions src/analytics/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ const POSTHOG_PROJECT_API_KEY = "CdDd2A0jKTI2vFAsrI9JWm3MqpOcgHz1bMyogAcwsE4";

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

const CACHE_FILE_PATH =
process.env.WASP_ANALYTICS_CACHED_EVENTS_JSON_PATH ??
"./wasp-analytics-cached-events.json";

export interface PosthogEvent {
distinct_id: string;
timestamp: Date;
Expand Down Expand Up @@ -137,17 +141,14 @@ async function fetchEvents({
};
}

// NOTE: This file is gitignored. If you change its name, update it also in gitignore.
const cachedEventsFilePath = "wasp-analytics-cached-events.json";

// Returns: [PosthogEvent]
// where events are guaranteed to be continuous, with no missing events between the cached events.
// Newest event is first (index 0), and oldest event is last, and cached events are continuous,
// in the sense that there is no events between the oldest and newest that is missing.
// There might be missing events before or after though.
async function loadCachedEvents(): Promise<PosthogEvent[]> {
try {
return JSON.parse(await fs.readFile(cachedEventsFilePath, "utf-8"));
return JSON.parse(await fs.readFile(CACHE_FILE_PATH, "utf-8"));
} catch (e) {
if (e.code === "ENOENT") return [];
throw e;
Expand All @@ -156,7 +157,7 @@ async function loadCachedEvents(): Promise<PosthogEvent[]> {

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

function getOldestEventTimestampOrNull(events: PosthogEvent[]): Date {
Expand Down

0 comments on commit 82629ef

Please sign in to comment.