import { Injectable } from '@nestjs/common'; import { DataSource } from 'typeorm'; import { SQL_PROCEDURES_PATH } from '@app/common/constants/sql-query-path'; import { SqlLoaderService } from './sql-loader.service'; @Injectable() export class OccupancyService { constructor( private readonly sqlLoader: SqlLoaderService, private readonly dataSource: DataSource, ) {} async updateOccupancyDataProcedures(): Promise { try { const { dateStr } = this.getFormattedDates(); // Execute all procedures in parallel await Promise.all([ this.executeProcedureWithRetry( 'procedure_update_fact_space_occupancy', [dateStr], 'fact_space_occupancy_count', ), this.executeProcedureWithRetry( 'procedure_update_daily_space_occupancy_duration', [dateStr], 'fact_daily_space_occupancy_duration', ), ]); } catch (err) { console.error('Failed to update occupancy data:', err); throw err; } } private getFormattedDates(): { dateStr: string } { const now = new Date(); return { dateStr: now.toLocaleDateString('en-CA'), // YYYY-MM-DD }; } private async executeProcedureWithRetry( procedureFileName: string, params: (string | number | null)[], folderName: string, retries = 3, ): Promise { try { const query = this.loadQuery(folderName, procedureFileName); await this.dataSource.query(query, params); console.log(`Procedure ${procedureFileName} executed successfully.`); } catch (err) { if (retries > 0) { const delayMs = 1000 * (4 - retries); // Exponential backoff console.warn(`Retrying ${procedureFileName} (${retries} retries left)`); await new Promise((resolve) => setTimeout(resolve, delayMs)); return this.executeProcedureWithRetry( procedureFileName, params, folderName, retries - 1, ); } console.error(`Failed to execute ${procedureFileName}:`, err); throw err; } } private loadQuery(folderName: string, fileName: string): string { return this.sqlLoader.loadQuery(folderName, fileName, SQL_PROCEDURES_PATH); } }