Skip to content

Commit bdebfaa

Browse files
First iteration: Status monitoring from andreasmolnardev/jobs-status-monitoring
First iteration: Status monitoring
2 parents e9e1f49 + 5c6c6b0 commit bdebfaa

98 files changed

Lines changed: 2836 additions & 94 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import { getServerPB } from '@/lib/pb';
2+
import { NextResponse } from 'next/server';
3+
import { ClientResponseError } from 'pocketbase';
4+
5+
// Define the structure for the response object
6+
interface JobStatusResponse {
7+
[jobId: string]: {
8+
status: string;
9+
dateChanged: string | null;
10+
durationChanged: number | null; // Duration in milliseconds
11+
};
12+
}
13+
14+
export async function GET(request: Request) {
15+
try {
16+
// --- auth ---
17+
const authHeader = request.headers.get('authorization');
18+
if (!authHeader?.startsWith('Bearer ')) {
19+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
20+
}
21+
const token = authHeader.split(' ')[1];
22+
const pb = getServerPB();
23+
pb.authStore.save(token, null);
24+
25+
let authModel;
26+
try {
27+
// Verify the token is valid and get the user record
28+
authModel = await pb.collection('users').authRefresh();
29+
} catch (err) {
30+
if (err instanceof ClientResponseError && err.status === 401) {
31+
// Token is invalid or expired
32+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
33+
}
34+
// Re-throw other errors
35+
throw err;
36+
}
37+
38+
const { searchParams } = new URL(request.url);
39+
const jobId = searchParams.get('jobId');
40+
41+
let monitoringJobs;
42+
43+
if (jobId) {
44+
monitoringJobs = await pb
45+
.collection('monitoringJobs')
46+
.getFullList({
47+
filter: `id = "${jobId}" && userId = "${authModel.record.id}"`,
48+
});
49+
50+
// If jobId exists but doesn't belong to this user or doesn't exist → return empty
51+
if (!monitoringJobs || monitoringJobs.length === 0) {
52+
return NextResponse.json({}, { status: 200 });
53+
}
54+
} else {
55+
monitoringJobs = await pb
56+
.collection('monitoringJobs')
57+
.getFullList({
58+
filter: `userId = "${authModel.record.id}"`,
59+
});
60+
}
61+
62+
if (!monitoringJobs || monitoringJobs.length === 0) {
63+
return NextResponse.json({}, { status: 200 });
64+
}
65+
66+
// --- Process Jobs and Fetch Logs Iteratively ---
67+
const results: JobStatusResponse = {};
68+
69+
for (const job of monitoringJobs) {
70+
71+
72+
const jobLogsResponse = await pb
73+
.collection('monitoringJobStatusLogs')
74+
.getList(1, 2, {
75+
filter: `job = "${job.id}" && job.userId = "${authModel.record.id}"`,
76+
sort: '-created'
77+
});
78+
79+
80+
const jobLogs = jobLogsResponse.items; // this contains the 2 most recent logs
81+
82+
// Default values
83+
let latestStatus = job.status; // Default to the job's own status (e.g., 'disabled')
84+
let dateChanged: string | null = null;
85+
let durationChanged: number | null = null;
86+
87+
if (jobLogs && jobLogs.length > 0) {
88+
// We have at least one log.
89+
const latestLog = jobLogs[0];
90+
91+
latestStatus = latestLog.status;
92+
dateChanged = latestLog.created;
93+
94+
95+
if (jobLogs.length > 1) {
96+
const secondLatestLog = jobLogs[1];
97+
98+
const latestDate = new Date(latestLog.created);
99+
const secondLatestDate = new Date(secondLatestLog.created);
100+
101+
durationChanged = (latestDate.getTime() - secondLatestDate.getTime()) / 1000; //in seconds
102+
}
103+
104+
}
105+
106+
// Add the computed data to our result object
107+
results[job.source] = {
108+
status: latestStatus,
109+
dateChanged: dateChanged,
110+
durationChanged: durationChanged,
111+
};
112+
}
113+
114+
// Return the latest map
115+
return NextResponse.json(results, { status: 200 });
116+
117+
} catch (error) {
118+
// enhanced logging so PocketBase error payload is visible
119+
console.error('Error fetching monitoring job statuses:', error);
120+
try {
121+
// Log the full PocketBase error response if available
122+
console.error('error.response:', JSON.stringify((error as any).response, Object.getOwnPropertyNames(error)));
123+
console.error('error.response?.data:', JSON.stringify((error as any).response?.data));
124+
} catch (e) {
125+
console.error('failed to stringify pocketbase error details', e);
126+
}
127+
return NextResponse.json({ error: 'Failed to fetch monitoring job statuses' }, { status: 500 });
128+
}
129+
}

0 commit comments

Comments
 (0)