mirror of
https://github.com/PreMiD/PreMiD.git
synced 2026-04-06 04:41:58 +02:00
Compare commits
2 Commits
api-worker
...
api-master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e63e1270aa | ||
|
|
f730e71bbf |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@premid/api-master",
|
||||
"type": "module",
|
||||
"version": "0.0.21",
|
||||
"version": "0.0.22",
|
||||
"private": true,
|
||||
"description": "PreMiD's api master",
|
||||
"license": "MPL-2.0",
|
||||
|
||||
40
apps/api-master/src/functions/updateActivePresenceGauge.ts
Normal file
40
apps/api-master/src/functions/updateActivePresenceGauge.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { redis } from "../index.js";
|
||||
import { activePresenceGauge } from "../tracing.js";
|
||||
|
||||
//* Track previously recorded services
|
||||
const previousServices = new Set<string>();
|
||||
|
||||
//* Function to update the gauge with per-service counts
|
||||
export async function updateActivePresenceGauge() {
|
||||
const pattern = "pmd-api.heartbeatUpdates.*.*";
|
||||
let cursor: string = "0";
|
||||
const serviceCounts = new Map<string, number>();
|
||||
|
||||
do {
|
||||
const [newCursor, keys] = await redis.scan(cursor, "MATCH", pattern, "COUNT", 1000); //* Use SCAN with COUNT for memory efficiency
|
||||
cursor = newCursor;
|
||||
for (const key of keys) {
|
||||
const parts = key.split(".");
|
||||
const service = parts[parts.length - 1]!;
|
||||
const hash = await redis.hgetall(key);
|
||||
const version = hash.version; //* Get version from hash
|
||||
serviceCounts.set(`${service}:${version}`, (serviceCounts.get(`${service}:${version}`) || 0) + 1);
|
||||
}
|
||||
} while (cursor !== "0");
|
||||
|
||||
// Set current counts and remove from previousServices
|
||||
serviceCounts.forEach((count, serviceVersion) => {
|
||||
const [service, version] = serviceVersion.split(":");
|
||||
activePresenceGauge.record(count, { service, version }); //* Include version in labels
|
||||
previousServices.delete(serviceVersion);
|
||||
});
|
||||
|
||||
// Set gauge to 0 for services that are no longer active
|
||||
previousServices.forEach((serviceVersion) => {
|
||||
const [service, version] = serviceVersion.split(":");
|
||||
activePresenceGauge.record(0, { service, version });
|
||||
});
|
||||
|
||||
// Update the set of previous services
|
||||
serviceCounts.forEach((_, serviceVersion) => previousServices.add(serviceVersion));
|
||||
}
|
||||
@@ -5,12 +5,13 @@ import { clearOldSessions } from "./functions/clearOldSessions.js";
|
||||
import createRedis from "./functions/createRedis.js";
|
||||
import { setCounter } from "./functions/setCounter.js";
|
||||
import "./tracing.js";
|
||||
import { updateActivePresenceGauge } from "./functions/updateActivePresenceGauge.js"; //* Added import
|
||||
|
||||
export const redis = createRedis();
|
||||
|
||||
export const mainLog = debug("api-master");
|
||||
|
||||
debug("Starting cron job to clear old sessions");
|
||||
debug("Starting cron jobs");
|
||||
|
||||
void new CronJob(
|
||||
// Every 5 seconds
|
||||
@@ -31,3 +32,13 @@ void new CronJob(
|
||||
undefined,
|
||||
true,
|
||||
);
|
||||
|
||||
void new CronJob(
|
||||
// Every 5 seconds
|
||||
"*/5 * * * * *",
|
||||
() => {
|
||||
updateActivePresenceGauge();
|
||||
},
|
||||
undefined,
|
||||
true,
|
||||
);
|
||||
|
||||
@@ -15,4 +15,10 @@ export const counter = meter.createUpDownCounter("active_activites", {
|
||||
valueType: ValueType.INT,
|
||||
});
|
||||
|
||||
// * Replace Observable Gauge with regular Gauge
|
||||
export const activePresenceGauge = meter.createGauge("active_presence_names", {
|
||||
description: "Number of active presence names per service",
|
||||
valueType: ValueType.INT,
|
||||
});
|
||||
|
||||
prometheusExporter.startServer();
|
||||
|
||||
@@ -47,7 +47,7 @@ export default async function createServer() {
|
||||
maxDepthPlugin(),
|
||||
maxDirectivesPlugin(),
|
||||
maxTokensPlugin(),
|
||||
useSentry(),
|
||||
/* useSentry(), */
|
||||
],
|
||||
schema: createSchema<FastifyContext>({
|
||||
resolvers,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { type } from "arktype";
|
||||
import type { MutationResolvers } from "../../../../generated/graphql-v5.js";
|
||||
import { redis } from "../../../../functions/createServer.js";
|
||||
|
||||
const heartbeatSchema = type({
|
||||
identifier: "string.uuid & string.lower",
|
||||
presences: {
|
||||
presence: {
|
||||
service: "string.trim",
|
||||
version: "string.semver",
|
||||
language: "string.trim",
|
||||
@@ -25,13 +26,21 @@ const mutation: MutationResolvers["heartbeat"] = async (_parent, input) => {
|
||||
if (out instanceof type.errors)
|
||||
throw new Error(out.summary);
|
||||
|
||||
// ! Disabled for now
|
||||
/* await redis.setex(
|
||||
`pmd-api.heartbeatUpdates.${data.identifier}`,
|
||||
// 5 minutes
|
||||
300,
|
||||
JSON.stringify(data)
|
||||
); */
|
||||
// * Use Redis Hash with 'service' in the key to store heartbeat data
|
||||
const redisKey = `pmd-api.heartbeatUpdates.${out.identifier}.${out.presence.service}`;
|
||||
await redis.hset(redisKey, {
|
||||
service: out.presence.service,
|
||||
version: out.presence.version,
|
||||
language: out.presence.language,
|
||||
since: out.presence.since.toString(),
|
||||
extension_version: out.extension.version,
|
||||
extension_language: out.extension.language,
|
||||
extension_connected_app: out.extension.connected?.app?.toString() || "",
|
||||
extension_connected_discord: out.extension.connected?.discord?.toString() || "",
|
||||
});
|
||||
await redis.expire(redisKey, 5);
|
||||
|
||||
// * End the custom metric or adjust as needed
|
||||
|
||||
return {
|
||||
__typename: "HeartbeatResult",
|
||||
|
||||
@@ -3,8 +3,6 @@ import process from "node:process";
|
||||
import * as Sentry from "@sentry/node";
|
||||
import { connect } from "mongoose";
|
||||
import "./tracing.js";
|
||||
|
||||
// eslint-disable-next-line perfectionist/sort-imports
|
||||
import createServer from "./functions/createServer.js";
|
||||
|
||||
// TODO SETUP SENTRY
|
||||
|
||||
Reference in New Issue
Block a user