server: scheduled background jobs

Add node-cron jobs for periodic market price updates, mission
generation, and world event generation; all wired through a central
scheduler module.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 23:42:04 +02:00
parent fb62a39dab
commit a998bb9704
4 changed files with 317 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
import { balance } from '../config/gameBalance.js';
import { prisma } from '../db/prisma.js';
import { getActiveEvents, priceModifierForCity } from '../modules/events/events.service.js';
import { clampDemandSupply, computePrices } from '../modules/market/pricing.js';
import { emitGlobal } from '../realtime/socket.js';
/**
* Tick del mercato (ogni minuto): domanda e offerta tornano lentamente
* verso l'equilibrio e i prezzi vengono ricalcolati con i modificatori
* degli eventi attivi.
*/
export async function updateMarketPrices(): Promise<void> {
const m = balance.market;
const [events, prices] = await Promise.all([
getActiveEvents(),
prisma.marketPrice.findMany({ include: { item: true, city: true } }),
]);
const updates = prices.map((price) => {
const demand = clampDemandSupply(
price.demand * m.decayFactor + m.equilibrium * (1 - m.decayFactor),
);
const supply = clampDemandSupply(
price.supply * m.decayFactor + m.equilibrium * (1 - m.decayFactor),
);
const next = computePrices(
price.item.basePrice,
price.city.economyModifier,
demand,
supply,
priceModifierForCity(events, price.cityId),
);
return prisma.marketPrice.update({
where: { cityId_itemId: { cityId: price.cityId, itemId: price.itemId } },
data: { demand, supply, buyPrice: next.buyPrice, sellPrice: next.sellPrice },
});
});
await prisma.$transaction(updates);
emitGlobal('market:updated', { updatedAt: new Date().toISOString() });
}