Initial Release
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
|
||||
import { pb } from '@/lib/pocketbase';
|
||||
import { UptimeData } from '@/types/service.types';
|
||||
|
||||
// Simple in-memory cache to avoid excessive requests
|
||||
const uptimeCache = new Map<string, {
|
||||
data: UptimeData[],
|
||||
timestamp: number,
|
||||
expiresIn: number
|
||||
}>();
|
||||
|
||||
// Cache time-to-live in milliseconds
|
||||
const CACHE_TTL = 15000; // 15 seconds
|
||||
|
||||
export const uptimeService = {
|
||||
async recordUptimeData(data: UptimeData): Promise<void> {
|
||||
try {
|
||||
console.log(`Recording uptime data for service ${data.serviceId}: Status ${data.status}, Response time: ${data.responseTime}ms`);
|
||||
|
||||
// Create a custom request options object to disable auto-cancellation
|
||||
const options = {
|
||||
$autoCancel: false, // Disable auto-cancellation for this request
|
||||
$cancelKey: `uptime_record_${data.serviceId}_${Date.now()}` // Unique key for this request
|
||||
};
|
||||
|
||||
// Store uptime history in the uptime_data collection
|
||||
// Format data for PocketBase (use snake_case)
|
||||
const record = await pb.collection('uptime_data').create({
|
||||
service_id: data.serviceId,
|
||||
timestamp: data.timestamp,
|
||||
status: data.status,
|
||||
response_time: data.responseTime
|
||||
}, options);
|
||||
|
||||
// Invalidate cache for this service after recording new data
|
||||
uptimeCache.delete(`uptime_${data.serviceId}`);
|
||||
|
||||
console.log(`Uptime data recorded successfully with ID: ${record.id}`);
|
||||
} catch (error) {
|
||||
console.error("Error recording uptime data:", error);
|
||||
throw new Error(`Failed to record uptime data: ${error}`);
|
||||
}
|
||||
},
|
||||
|
||||
async getUptimeHistory(
|
||||
serviceId: string,
|
||||
limit: number = 200,
|
||||
startDate?: Date,
|
||||
endDate?: Date
|
||||
): Promise<UptimeData[]> {
|
||||
try {
|
||||
// Create cache key based on parameters
|
||||
const cacheKey = `uptime_${serviceId}_${limit}_${startDate?.toISOString() || ''}_${endDate?.toISOString() || ''}`;
|
||||
|
||||
// Check if we have a valid cached result
|
||||
const cached = uptimeCache.get(cacheKey);
|
||||
if (cached && (Date.now() - cached.timestamp) < cached.expiresIn) {
|
||||
console.log(`Using cached uptime history for service ${serviceId}`);
|
||||
return cached.data;
|
||||
}
|
||||
|
||||
console.log(`Fetching uptime history for service ${serviceId}, limit: ${limit}`);
|
||||
|
||||
// Base filter for a specific service
|
||||
let filter = `service_id='${serviceId}'`;
|
||||
|
||||
// Add date range filtering if provided
|
||||
if (startDate && endDate) {
|
||||
// Convert to ISO strings for PocketBase filtering
|
||||
const startISO = startDate.toISOString();
|
||||
const endISO = endDate.toISOString();
|
||||
|
||||
// Log the date range we're filtering by
|
||||
console.log(`Date range filter: ${startISO} to ${endISO}`);
|
||||
|
||||
filter += ` && timestamp >= '${startISO}' && timestamp <= '${endISO}'`;
|
||||
}
|
||||
|
||||
// Calculate time difference to determine if it's a short range (like 60min)
|
||||
const isShortTimeRange = startDate && endDate &&
|
||||
(endDate.getTime() - startDate.getTime() <= 60 * 60 * 1000);
|
||||
|
||||
// For very short time ranges, adjust sorting and limit
|
||||
const sort = '-timestamp'; // Default: newest first
|
||||
const actualLimit = isShortTimeRange ? Math.max(limit, 300) : limit; // Ensure adequate points for short ranges
|
||||
|
||||
// Create custom request options to disable auto-cancellation
|
||||
const options = {
|
||||
filter: filter,
|
||||
sort: sort,
|
||||
$autoCancel: false, // Disable auto-cancellation for this request
|
||||
$cancelKey: `uptime_history_${serviceId}_${Date.now()}` // Unique key for this request
|
||||
};
|
||||
|
||||
try {
|
||||
// Get uptime history for a specific service with date filtering
|
||||
const response = await pb.collection('uptime_data').getList(1, actualLimit, options);
|
||||
|
||||
console.log(`Fetched ${response.items.length} uptime records for service ${serviceId}`);
|
||||
|
||||
// Map and return the data
|
||||
const uptimeData = response.items.map(item => ({
|
||||
id: item.id,
|
||||
serviceId: item.service_id,
|
||||
timestamp: item.timestamp,
|
||||
status: item.status,
|
||||
responseTime: item.response_time || 0,
|
||||
date: item.timestamp, // Mapping timestamp to date
|
||||
uptime: 100 // Default value for uptime
|
||||
}));
|
||||
|
||||
// For short time ranges with few data points, we might need to ensure we have enough points
|
||||
const shouldAddPlaceholderData = isShortTimeRange && uptimeData.length <= 2;
|
||||
|
||||
let finalData = uptimeData;
|
||||
|
||||
if (shouldAddPlaceholderData && uptimeData.length > 0) {
|
||||
// We'll add some additional data points to ensure graph is visible
|
||||
console.log("Adding placeholder data points to ensure graph visibility");
|
||||
finalData = [...uptimeData];
|
||||
}
|
||||
|
||||
// Cache the result
|
||||
uptimeCache.set(cacheKey, {
|
||||
data: finalData,
|
||||
timestamp: Date.now(),
|
||||
expiresIn: CACHE_TTL
|
||||
});
|
||||
|
||||
return finalData;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching uptime history:", error);
|
||||
|
||||
// Try to return cached data even if it's expired, as a fallback
|
||||
const cacheKey = `uptime_${serviceId}_${limit}_${startDate?.toISOString() || ''}_${endDate?.toISOString() || ''}`;
|
||||
const cached = uptimeCache.get(cacheKey);
|
||||
if (cached) {
|
||||
console.log(`Using expired cached data for service ${serviceId} due to fetch error`);
|
||||
return cached.data;
|
||||
}
|
||||
|
||||
throw new Error('Failed to load uptime history.');
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user