Merge branch 'main' into dev

This commit is contained in:
Owen
2026-02-22 21:02:58 -08:00
16 changed files with 249 additions and 65 deletions

View File

@@ -46,8 +46,6 @@ export class UsageService {
return null;
}
let orgIdToUse = await this.getBillingOrg(orgId, transaction);
// Truncate value to 11 decimal places
value = this.truncateValue(value);
@@ -59,6 +57,7 @@ export class UsageService {
try {
let usage;
if (transaction) {
const orgIdToUse = await this.getBillingOrg(orgId, transaction);
usage = await this.internalAddUsage(
orgIdToUse,
featureId,
@@ -67,6 +66,7 @@ export class UsageService {
);
} else {
await db.transaction(async (trx) => {
const orgIdToUse = await this.getBillingOrg(orgId, trx);
usage = await this.internalAddUsage(
orgIdToUse,
featureId,
@@ -92,7 +92,7 @@ export class UsageService {
const delay = baseDelay + jitter;
logger.warn(
`Deadlock detected for ${orgIdToUse}/${featureId}, retrying attempt ${attempt}/${maxRetries} after ${delay.toFixed(0)}ms`
`Deadlock detected for ${orgId}/${featureId}, retrying attempt ${attempt}/${maxRetries} after ${delay.toFixed(0)}ms`
);
await new Promise((resolve) => setTimeout(resolve, delay));
@@ -100,7 +100,7 @@ export class UsageService {
}
logger.error(
`Failed to add usage for ${orgIdToUse}/${featureId} after ${attempt} attempts:`,
`Failed to add usage for ${orgId}/${featureId} after ${attempt} attempts:`,
error
);
break;
@@ -169,7 +169,7 @@ export class UsageService {
return;
}
let orgIdToUse = await this.getBillingOrg(orgId);
const orgIdToUse = await this.getBillingOrg(orgId);
try {
// Truncate value to 11 decimal places if provided
@@ -227,7 +227,7 @@ export class UsageService {
orgId: string,
featureId: FeatureId
): Promise<string | null> {
let orgIdToUse = await this.getBillingOrg(orgId);
const orgIdToUse = await this.getBillingOrg(orgId);
const cacheKey = `customer_${orgIdToUse}_${featureId}`;
const cached = cache.get<string>(cacheKey);
@@ -274,7 +274,7 @@ export class UsageService {
return null;
}
let orgIdToUse = await this.getBillingOrg(orgId, trx);
const orgIdToUse = await this.getBillingOrg(orgId, trx);
const usageId = `${orgIdToUse}-${featureId}`;
@@ -382,7 +382,7 @@ export class UsageService {
return false;
}
let orgIdToUse = await this.getBillingOrg(orgId, trx);
const orgIdToUse = await this.getBillingOrg(orgId, trx);
// This method should check the current usage against the limits set for the organization
// and kick out all of the sites on the org

View File

@@ -78,7 +78,8 @@ export async function getOrgTierData(
if (
subscription.type === "tier1" ||
subscription.type === "tier2" ||
subscription.type === "tier3"
subscription.type === "tier3" ||
subscription.type === "enterprise"
) {
tier = subscription.type;
active = true;

View File

@@ -14,6 +14,9 @@
import { config } from "@server/lib/config";
import logger from "@server/logger";
import { redis } from "#private/lib/redis";
import { v4 as uuidv4 } from "uuid";
const instanceId = uuidv4();
export class LockManager {
/**
@@ -33,7 +36,7 @@ export class LockManager {
}
const lockValue = `${
config.getRawConfig().gerbil.exit_node_name
instanceId
}:${Date.now()}`;
const redisKey = `lock:${lockKey}`;
@@ -52,7 +55,7 @@ export class LockManager {
if (result === "OK") {
logger.debug(
`Lock acquired: ${lockKey} by ${
config.getRawConfig().gerbil.exit_node_name
instanceId
}`
);
return true;
@@ -63,14 +66,14 @@ export class LockManager {
if (
existingValue &&
existingValue.startsWith(
`${config.getRawConfig().gerbil.exit_node_name}:`
`${instanceId}:`
)
) {
// Extend the lock TTL since it's the same worker
await redis.pexpire(redisKey, ttlMs);
logger.debug(
`Lock extended: ${lockKey} by ${
config.getRawConfig().gerbil.exit_node_name
instanceId
}`
);
return true;
@@ -116,7 +119,7 @@ export class LockManager {
local key = KEYS[1]
local worker_prefix = ARGV[1]
local current_value = redis.call('GET', key)
if current_value and string.find(current_value, worker_prefix, 1, true) == 1 then
return redis.call('DEL', key)
else
@@ -129,19 +132,19 @@ export class LockManager {
luaScript,
1,
redisKey,
`${config.getRawConfig().gerbil.exit_node_name}:`
`${instanceId}:`
)) as number;
if (result === 1) {
logger.debug(
`Lock released: ${lockKey} by ${
config.getRawConfig().gerbil.exit_node_name
instanceId
}`
);
} else {
logger.warn(
`Lock not released - not owned by worker: ${lockKey} by ${
config.getRawConfig().gerbil.exit_node_name
instanceId
}`
);
}
@@ -198,7 +201,7 @@ export class LockManager {
const ownedByMe =
exists &&
value!.startsWith(
`${config.getRawConfig().gerbil.exit_node_name}:`
`${instanceId}:`
);
const owner = exists ? value!.split(":")[0] : undefined;
@@ -233,7 +236,7 @@ export class LockManager {
local worker_prefix = ARGV[1]
local ttl = tonumber(ARGV[2])
local current_value = redis.call('GET', key)
if current_value and string.find(current_value, worker_prefix, 1, true) == 1 then
return redis.call('PEXPIRE', key, ttl)
else
@@ -246,14 +249,14 @@ export class LockManager {
luaScript,
1,
redisKey,
`${config.getRawConfig().gerbil.exit_node_name}:`,
`${instanceId}:`,
ttlMs.toString()
)) as number;
if (result === 1) {
logger.debug(
`Lock extended: ${lockKey} by ${
config.getRawConfig().gerbil.exit_node_name
instanceId
} for ${ttlMs}ms`
);
return true;
@@ -356,7 +359,7 @@ export class LockManager {
(value) =>
value &&
value.startsWith(
`${config.getRawConfig().gerbil.exit_node_name}:`
`${instanceId}:`
)
).length;
}

View File

@@ -72,15 +72,15 @@ export const privateConfigSchema = z.object({
db: z.int().nonnegative().optional().default(0)
})
)
.optional(),
tls: z
.object({
rejectUnauthorized: z
.boolean()
.optional()
.default(true)
})
.optional()
// tls: z
// .object({
// reject_unauthorized: z
// .boolean()
// .optional()
// .default(true)
// })
// .optional()
})
.optional(),
gerbil: z

View File

@@ -108,11 +108,15 @@ class RedisManager {
port: redisConfig.port!,
password: redisConfig.password,
db: redisConfig.db
// tls: {
// rejectUnauthorized:
// redisConfig.tls?.reject_unauthorized || false
// }
};
// Enable TLS if configured (required for AWS ElastiCache in-transit encryption)
if (redisConfig.tls) {
opts.tls = {
rejectUnauthorized: redisConfig.tls.rejectUnauthorized ?? true
};
}
return opts;
}
@@ -130,11 +134,15 @@ class RedisManager {
port: replica.port!,
password: replica.password,
db: replica.db || redisConfig.db
// tls: {
// rejectUnauthorized:
// replica.tls?.reject_unauthorized || false
// }
};
// Enable TLS if configured (required for AWS ElastiCache in-transit encryption)
if (redisConfig.tls) {
opts.tls = {
rejectUnauthorized: redisConfig.tls.rejectUnauthorized ?? true
};
}
return opts;
}

View File

@@ -197,7 +197,6 @@ export async function updateSiteBandwidth(
usageService
.checkLimitSet(
orgId,
FeatureId.EGRESS_DATA_MB,
bandwidthUsage
)

View File

@@ -2,9 +2,13 @@ import { db, dnsRecords } from "@server/db";
import { domains, exitNodes, orgDomains, orgs, resources } from "@server/db";
import config from "@server/lib/config";
import { eq, ne } from "drizzle-orm";
import logger from "@server/logger";
import { build } from "@server/build";
export async function copyInConfig() {
if (build == "saas") {
return;
}
const endpoint = config.getRawConfig().gerbil.base_endpoint;
const listenPort = config.getRawConfig().gerbil.start_port;

View File

@@ -19,6 +19,7 @@ import m11 from "./scriptsPg/1.14.0";
import m12 from "./scriptsPg/1.15.0";
import m13 from "./scriptsPg/1.15.3";
import m14 from "./scriptsPg/1.15.4";
import { build } from "@server/build";
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
// EXCEPT FOR THE DATABASE AND THE SCHEMA
@@ -53,6 +54,10 @@ async function run() {
}
export async function runMigrations() {
if (build == "saas") {
console.log("Running in SaaS mode, skipping migrations...");
return;
}
if (process.env.DISABLE_MIGRATIONS) {
console.log("Migrations are disabled. Skipping...");
return;

View File

@@ -37,6 +37,7 @@ import m32 from "./scriptsSqlite/1.14.0";
import m33 from "./scriptsSqlite/1.15.0";
import m34 from "./scriptsSqlite/1.15.3";
import m35 from "./scriptsSqlite/1.15.4";
import { build } from "@server/build";
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
// EXCEPT FOR THE DATABASE AND THE SCHEMA
@@ -105,6 +106,10 @@ function backupDb() {
}
export async function runMigrations() {
if (build == "saas") {
console.log("Running in SaaS mode, skipping migrations...");
return;
}
if (process.env.DISABLE_MIGRATIONS) {
console.log("Migrations are disabled. Skipping...");
return;