mirror of
https://github.com/orangecoding/fredy.git
synced 2026-06-16 12:31:07 +00:00
storing last run in database
This commit is contained in:
@@ -20,6 +20,28 @@ function cap(val) {
|
||||
return String(val).charAt(0).toUpperCase() + String(val).slice(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the most recent job trigger timestamp across the given jobs.
|
||||
*
|
||||
* Returns `null` when none of the jobs has ever been triggered. The value is
|
||||
* persisted per-job via `jobs.last_run_at`, so the dashboard reflects the
|
||||
* scope visible to the current user (own + shared, or all for admins) rather
|
||||
* than a process-wide in-memory value.
|
||||
*
|
||||
* @param {Array<{lastRunAt?: number|null}>} jobs
|
||||
* @returns {number|null}
|
||||
*/
|
||||
function computeLastRun(jobs) {
|
||||
let lastRun = null;
|
||||
for (const job of jobs) {
|
||||
const ts = job.lastRunAt;
|
||||
if (typeof ts === 'number' && (lastRun == null || ts > lastRun)) {
|
||||
lastRun = ts;
|
||||
}
|
||||
}
|
||||
return lastRun;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('fastify').FastifyInstance} fastify
|
||||
*/
|
||||
@@ -46,11 +68,13 @@ export default async function dashboardPlugin(fastify) {
|
||||
}
|
||||
: { labels: [], values: [] };
|
||||
|
||||
const lastRun = computeLastRun(jobs);
|
||||
|
||||
return {
|
||||
general: {
|
||||
interval: settings.interval,
|
||||
lastRun: settings.lastRun || null,
|
||||
nextRun: settings.lastRun == null ? 0 : settings.lastRun + settings.interval * 60000,
|
||||
lastRun,
|
||||
nextRun: lastRun == null ? 0 : lastRun + settings.interval * 60000,
|
||||
},
|
||||
kpis: {
|
||||
totalJobs,
|
||||
|
||||
@@ -104,7 +104,6 @@ export function initJobExecutionService({ providers, settings, intervalMs }) {
|
||||
logger.debug('Working hours set. Skipping as outside of working hours.');
|
||||
return;
|
||||
}
|
||||
settings.lastRun = now;
|
||||
const jobs = jobStorage.getJobs().filter((job) => {
|
||||
if (!context) return true; // startup/cron → all
|
||||
if (context.isAdmin) return true; // admin → all
|
||||
@@ -150,6 +149,13 @@ export function initJobExecutionService({ providers, settings, intervalMs }) {
|
||||
}
|
||||
const acquired = markRunning(job.id);
|
||||
if (!acquired) return;
|
||||
// Persist the trigger time so the dashboard "last search" KPI can be
|
||||
// derived per accessible user without an in-memory cache.
|
||||
try {
|
||||
jobStorage.updateJobLastRunAt(job.id, Date.now());
|
||||
} catch (err) {
|
||||
logger.warn('Failed to persist last_run_at for job', job.id, err);
|
||||
}
|
||||
// notify listeners (SSE) that the job started
|
||||
try {
|
||||
bus.emit('jobs:status', { jobId: job.id, running: true });
|
||||
|
||||
@@ -97,6 +97,7 @@ export const getJob = (jobId) => {
|
||||
j.notification_adapter AS notificationAdapter,
|
||||
j.spatial_filter AS spatialFilter,
|
||||
j.spec_filter AS specFilter,
|
||||
j.last_run_at AS lastRunAt,
|
||||
(SELECT COUNT(1) FROM listings l WHERE l.job_id = j.id AND l.is_active = 1 AND l.manually_deleted = 0) AS numberOfFoundListings
|
||||
FROM jobs j
|
||||
WHERE j.id = @id
|
||||
@@ -116,6 +117,24 @@ export const getJob = (jobId) => {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Record the timestamp at which a job was last triggered.
|
||||
*
|
||||
* Called from the job execution service when a job starts running. The value
|
||||
* is persisted so that the dashboard "last search" KPI survives restarts and
|
||||
* can be computed per accessible user.
|
||||
*
|
||||
* @param {string} jobId - Job primary key.
|
||||
* @param {number} timestamp - Epoch milliseconds.
|
||||
* @returns {void}
|
||||
*/
|
||||
export const updateJobLastRunAt = (jobId, timestamp) => {
|
||||
SqliteConnection.execute(`UPDATE jobs SET last_run_at = @timestamp WHERE id = @id`, {
|
||||
id: jobId,
|
||||
timestamp,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Update job enabled status.
|
||||
* @param {{jobId: string, status: boolean}} params - Parameters.
|
||||
@@ -164,6 +183,7 @@ export const getJobs = () => {
|
||||
j.notification_adapter AS notificationAdapter,
|
||||
j.spatial_filter AS spatialFilter,
|
||||
j.spec_filter AS specFilter,
|
||||
j.last_run_at AS lastRunAt,
|
||||
(SELECT COUNT(1) FROM listings l WHERE l.job_id = j.id AND l.is_active = 1 AND l.manually_deleted = 0) AS numberOfFoundListings
|
||||
FROM jobs j
|
||||
WHERE j.enabled = 1
|
||||
@@ -269,6 +289,7 @@ export const queryJobs = ({
|
||||
j.notification_adapter AS notificationAdapter,
|
||||
j.spatial_filter AS spatialFilter,
|
||||
j.spec_filter AS specFilter,
|
||||
j.last_run_at AS lastRunAt,
|
||||
(SELECT COUNT(1) FROM listings l WHERE l.job_id = j.id AND l.is_active = 1 AND l.manually_deleted = 0) AS numberOfFoundListings
|
||||
FROM jobs j
|
||||
${whereSql}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2026 by Christian Kellner.
|
||||
* Licensed under Apache-2.0 with Commons Clause and Attribution/Naming Clause
|
||||
*/
|
||||
|
||||
/**
|
||||
* Migration: add `last_run_at` to the `jobs` table.
|
||||
*
|
||||
* Stores the epoch-ms timestamp at which a job was last triggered. Used by the
|
||||
* dashboard "last search" KPI so the value survives restarts and reflects the
|
||||
* actual jobs the requesting user can see (own, shared, or all for admins),
|
||||
* replacing the previous in-memory `settings.lastRun` value.
|
||||
*
|
||||
* NULL means the job has not yet been triggered since this column was added.
|
||||
*/
|
||||
export function up(db) {
|
||||
db.exec(`
|
||||
ALTER TABLE jobs ADD COLUMN last_run_at INTEGER
|
||||
`);
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
* @property {SpatialFilter | null} [spatialFilter] Optional spatial filter configuration as GeoJSON FeatureCollection.
|
||||
* @property {SpecFilter | null} [specFilter] Optional listing specifications.
|
||||
* @property {number} [numberOfFoundListings] Count of active listings for this job.
|
||||
* @property {number | null} [lastRunAt] Epoch ms at which the job was last triggered, or null if never triggered.
|
||||
*/
|
||||
|
||||
export {};
|
||||
|
||||
Reference in New Issue
Block a user