More service naming consistency cleanup

This commit is contained in:
Dominic Ferrando
2026-07-04 15:10:06 -04:00
parent f4aad56ad3
commit afdc8de77c
5 changed files with 113 additions and 102 deletions
+42 -33
View File
@@ -5,45 +5,46 @@ import { Value } from "@sinclair/typebox/value";
import { log } from "../util";
export class CalculatorService {
private calculator: LevelCalculator = new LevelCalculator(new Standards(DEFAULT_STANDARDS_DATASET));
standards: StandardsService = new StandardsService(this.calculator);
private Calculator = new LevelCalculator(new Standards(DEFAULT_STANDARDS_DATASET));
Standards: StandardsService = new StandardsService(this.Calculator);
calculate(player: Player, activityPerformances: ActivityPerformance[]) {
this.standards.refreshConfig({ onlyIfStale: true }).catch((err) => log.error({ err }, "failed to refresh standards config"));
return this.calculator.calculate(player, activityPerformances);
this.Standards.Config.refresh({ onlyIfStale: true }).catch((err) => log.error({ err }, "failed to refresh standards config"));
return this.Calculator.calculate(player, activityPerformances);
}
}
class StandardsService {
private static readonly CONFIG_REFRESH_INTERVAL_MS = 30_000;
Config: StandardsConfigService;
constructor(private Calculator: LevelCalculator) {
this.Config = new StandardsConfigService(this.Calculator);
}
}
class StandardsConfigService {
private static readonly REFRESH_INTERVAL_MS = 30_000;
private cachedParametersStringified: string | null = null;
private cachedDatasetId: string | null = null;
private lastRefreshedAt = 0;
constructor(private calculator: LevelCalculator) { }
constructor(private Calculator: LevelCalculator) { }
async getSelectedConfig(opt: { skipCache?: boolean } = {}): Promise<StandardsParameters> {
if (!opt.skipCache) return this.calculator.standards.params;
await this.refreshConfig();
return this.calculator.standards.params;
async create(datasetId: string, parameters: StandardsParameters) {
await db.insertInto("standards_configs")
.values({ parameters, dataset_id: datasetId })
.execute();
}
async selectConfig(id: string) {
await db.transaction().execute(async (trx) => {
await trx.updateTable("standards_configs")
.set({ is_selected: false })
.where("is_selected", "=", true)
.execute();
const result = await trx.updateTable("standards_configs")
.set({ is_selected: true })
.where("id", "=", id)
.execute();
if (result[0]?.numUpdatedRows === 0n) throw new Error(`No config with id "${id}"`);
});
/** Retrieves the currently selected configuration */
async get(opt: { skipCache?: boolean } = {}): Promise<StandardsParameters> {
if (!opt.skipCache) return this.Calculator.Standards.params;
await this.refresh();
return this.Calculator.Standards.params;
}
async setConfig(id: string, datasetId: string, parameters: StandardsParameters) {
async update(id: string, datasetId: string, parameters: StandardsParameters) {
const result = await db.updateTable("standards_configs")
.set({ parameters, dataset_id: datasetId })
.where("id", "=", id)
@@ -51,15 +52,9 @@ class StandardsService {
if (result[0]?.numUpdatedRows === 0n) throw new Error(`No config with id "${id}"`);
}
async createConfig(datasetId: string, parameters: StandardsParameters) {
await db.insertInto("standards_configs")
.values({ parameters, dataset_id: datasetId })
.execute();
}
async refreshConfig(opt: { onlyIfStale?: boolean } = {}) {
async refresh(opt: { onlyIfStale?: boolean } = {}) {
if (opt.onlyIfStale)
if (Date.now() - this.lastRefreshedAt < StandardsService.CONFIG_REFRESH_INTERVAL_MS) return;
if (Date.now() - this.lastRefreshedAt < StandardsConfigService.REFRESH_INTERVAL_MS) return;
this.lastRefreshedAt = Date.now();
@@ -79,8 +74,22 @@ class StandardsService {
const parametersStringified = JSON.stringify(config.parameters);
if (parametersStringified === this.cachedParametersStringified && config.datasetId === this.cachedDatasetId) return;
this.calculator.standards = new Standards(config.dataset, config.parameters);
this.Calculator.Standards = new Standards(config.dataset, config.parameters);
this.cachedParametersStringified = parametersStringified;
this.cachedDatasetId = config.datasetId;
}
async switch(id: string) {
await db.transaction().execute(async (trx) => {
await trx.updateTable("standards_configs")
.set({ is_selected: false })
.where("is_selected", "=", true)
.execute();
const result = await trx.updateTable("standards_configs")
.set({ is_selected: true })
.where("id", "=", id)
.execute();
if (result[0]?.numUpdatedRows === 0n) throw new Error(`No config with id "${id}"`);
});
}
}
+29 -28
View File
@@ -19,32 +19,33 @@ type QueuedSync = {
class AlreadyClaimedError extends Error { }
export class CommerceService {
public readonly printful: PrintfulClient;
public readonly webflow: WebflowClient;
private readonly productSyncer: ProductSyncer;
readonly queue: SyncQueue;
public readonly Printful = new PrintfulClient({
token: env.PRINTFUL_AUTH,
storeId: env.PRINTFUL_STORE_ID,
});
public readonly Webflow = new WebflowClient({
siteId: env.WEBFLOW_SITE_ID,
collectionsId: env.WEBFLOW_COLLECTION_ID,
token: env.WEBFLOW_AUTH,
webhookSecret: env.WEBFLOW_WEBHOOK_SECRET,
});
readonly Sync = new SyncService(this.Printful, this.Webflow);
}
constructor() {
this.printful = new PrintfulClient({
token: env.PRINTFUL_AUTH,
storeId: env.PRINTFUL_STORE_ID,
});
this.webflow = new WebflowClient({
siteId: env.WEBFLOW_SITE_ID,
collectionsId: env.WEBFLOW_COLLECTION_ID,
token: env.WEBFLOW_AUTH,
webhookSecret: env.WEBFLOW_WEBHOOK_SECRET,
});
this.productSyncer = new ProductSyncer(this.printful, this.webflow, log);
this.queue = new SyncQueue();
class SyncService {
readonly Queue = new SyncQueueService();
private readonly ProductSyncer: ProductSyncer;
constructor(private readonly Printful: PrintfulClient, private readonly Webflow: WebflowClient) {
this.ProductSyncer = new ProductSyncer(this.Printful, this.Webflow, log);
}
async sync(queuedSync: QueuedSync) {
async start(queuedSync: QueuedSync) {
let id = queuedSync.id ?? null;
let freedSlot = false;
try {
log.info({ session: queuedSync.session }, "starting sync run");
await this.productSyncer.sync({
await this.ProductSyncer.run({
filter: queuedSync.filter,
onStart: async (startDate) => {
const values: Insertable<ProductSyncs> = {
@@ -95,7 +96,7 @@ export class CommerceService {
return;
}
const activeSync = await this.getActiveSync();
const activeSync = await this.getActive();
const activeSyncConflict = activeSync && err instanceof DatabaseError && err.code === "23505";
if (activeSyncConflict) {
@@ -106,11 +107,11 @@ export class CommerceService {
.set({ syncing_printful_product_ids: [], ended_at: new Date(), has_failed: true })
.where("id", "=", activeSync.id)
.execute();
await this.sync(queuedSync);
await this.start(queuedSync);
}
else {
log.info("sync already active, enqueuing next sync");
await this.queue.enqueue(queuedSync);
await this.Queue.enqueue(queuedSync);
}
}
else {
@@ -127,8 +128,8 @@ export class CommerceService {
finally {
if (freedSlot) {
try {
const frontQueuedSync = await this.queue.front();
if (frontQueuedSync) await this.sync(frontQueuedSync);
const frontQueuedSync = await this.Queue.front();
if (frontQueuedSync) await this.start(frontQueuedSync);
}
catch (err) {
log.error({ err }, "failed to process next queued sync")
@@ -137,7 +138,7 @@ export class CommerceService {
}
}
async getActiveSync(sessionId?: string) {
async getActive(sessionId?: string) {
return await db.selectFrom("product_syncs")
.selectAll()
.$if(sessionId !== undefined, (qb) =>
@@ -149,7 +150,7 @@ export class CommerceService {
.executeTakeFirst();
}
async getLatestSync(sessionId?: string) {
async getLatest(sessionId?: string) {
return await db.selectFrom("product_syncs")
.selectAll()
.$if(sessionId !== undefined, (qb) =>
@@ -160,14 +161,14 @@ export class CommerceService {
.executeTakeFirst();
}
deriveSyncStatus(sync: Selectable<ProductSyncs>): SyncStatus {
deriveStatus(sync: Selectable<ProductSyncs>): SyncStatus {
if (!sync.started_at) return "queued";
if (!sync.ended_at) return "active";
return sync.has_failed ? "failed" : "succeeded";
}
}
class SyncQueue {
class SyncQueueService {
async enqueue(queuedSync: QueuedSync) {
const values: Insertable<ProductSyncs> = {
session_id: queuedSync.session.id,