Skip to content

Commit

Permalink
✨ Better env management
Browse files Browse the repository at this point in the history
  • Loading branch information
coyotte508 committed Apr 28, 2024
1 parent c0f85a1 commit 1223120
Show file tree
Hide file tree
Showing 9 changed files with 44 additions and 84 deletions.
2 changes: 2 additions & 0 deletions apps/api/.env.test.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
port=50606
silent=true
53 changes: 16 additions & 37 deletions apps/api/app/config/db.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,28 @@
import cluster from "cluster";
import locks from "mongo-locks";
import mongoose from "mongoose";
import { LockManager } from "mongo-locks";
import { migrate } from "../models/migrations";
import env from "./env";
import { MongoClient } from "mongodb";

mongoose.Promise = global.Promise; // native promises
const client = new MongoClient(env.database.bgs.url, { directConnection: true, ignoreUndefined: true });

let dbInit = false;
const db = client.db(env.database.bgs.name);

export default async function initDb(url = env.database.bgs.url, runMigrations = true) {
if (dbInit) {
console.log("DB already initialized");
return;
}

dbInit = true;

const connect = () =>
mongoose
.connect(url, { dbName: env.database.bgs.name, directConnection: true })
.then(() => console.log("successfully connected to database"));
await connect();
const locks = new LockManager(db.collection("mongo-locks"));

locks.init(mongoose.connection);
await db
.listCollections()
.toArray()
.then(() => {
console.log("Connected to database");
});

if (cluster.isMaster && runMigrations) {
let free = () => {};
try {
free = await locks.lock("migration");
await migrate();
} catch (err) {
console.error(err);
} finally {
free();
}
}
export const collections = {};

mongoose.connection.on("error", (err) => {
console.error("db error", err);
});
if (!env.isTest && cluster.isMaster) {
await using lock = await locks.lock("db");

if (!env.script) {
mongoose.connection.on("disconnected", () => {
console.log("attempt to reconnect to database");
setTimeout(() => connect().catch(console.error), 5000);
});
if (lock) {
await migrate();
}
}
18 changes: 17 additions & 1 deletion apps/api/app/config/env.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from "fs";
import os from "os";
import path from "path";
import dotenv from "dotenv";

const domain = process.env.domain || "boardgamers.space";
let dbName = process.env.dbName ?? "bgs";
Expand All @@ -11,9 +12,24 @@ if (process.env.NODE_ENV === "test") {
dbName += "-dev";
}

const environment = process.env.NODE_ENV || "development";

const parsedEnv = dotenv.config().parsed ?? {};
// Load non-sensitive default values for environment
const parsedDefaults = dotenv.config({ path: `.env.${environment}.example` }).parsed || {};

// Replace empty strings from the loaded envs by undefined
// An empty string in .env can still prevent the default value from being loaded
for (const key of [...Object.keys(parsedEnv), ...Object.keys(parsedDefaults)]) {
if (process.env[key] === "") {
delete process.env[key];
}
}

export default {
script: false,
domain,
isTest: process.env.NODE_ENV === "test",
site: process.env.site || `www.${domain}`,
noreply: process.env.noreply || `BGS <no-reply@${domain}>`,
contact: process.env.contact || `contact@${domain}`,
Expand Down Expand Up @@ -79,5 +95,5 @@ export default {
secret: process.env.googleSecret || "google-oauth-secret",
},
},
silent: false,
silent: process.env.silent === "true",
};
31 changes: 0 additions & 31 deletions apps/api/app/config/test-utils.ts

This file was deleted.

3 changes: 2 additions & 1 deletion apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"version": "1.3.1",
"license": "AGPL-3.0",
"private": true,
"type": "module",
"dependencies": {
"@bgs/models": "workspace:*",
"@bgs/types": "workspace:*",
Expand All @@ -13,7 +14,7 @@
"cookie-parser": "^1.4.3",
"date-fns": "^2.25.0",
"delay": "^3.1.0",
"dotenv": "^5.0.1",
"dotenv": "^16.4.5",
"http-errors": "^1.6.3",
"jimp": "^0.16.1",
"jsonwebtoken": "^8.5.1",
Expand Down
10 changes: 5 additions & 5 deletions apps/api/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions apps/api/scripts/seed.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import mongoose, { Collection } from "mongoose";
import { env } from "../app/config";
import initDb from "../app/config/db";
import * as models from "../app/models";
import * as data from "./data";

Expand Down
5 changes: 0 additions & 5 deletions apps/api/server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import cluster from "cluster";
import "dotenv/config";
import { listen } from "./app/app";
import initDb from "./app/config/db";
import env from "./app/config/env";
import { listen as listenResources } from "./app/resources";

Expand All @@ -10,8 +8,6 @@ const handleError = (err: Error) => {
process.exit(1);
};

initDb().catch(handleError);

// In production, run a process for each CPU
if (cluster.isMaster && env.isProduction && env.threads > 1) {
for (let i = 0; i < env.threads; i++) {
Expand All @@ -20,7 +16,6 @@ if (cluster.isMaster && env.isProduction && env.threads > 1) {
} else {
listen().catch(handleError);
listenResources().catch(handleError);
// tslint:disable-next-line no-var-requires
require("./app/ws");
}

Expand Down
4 changes: 2 additions & 2 deletions apps/api/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"module": "ESNext",
"moduleResolution": "node",
"sourceMap": true,
"outDir": "./dist",
"experimentalDecorators": true,
Expand Down

0 comments on commit 1223120

Please sign in to comment.