wekan/imports/cronMigrationClient.js

144 lines
5.3 KiB
JavaScript

import { Meteor } from 'meteor/meteor';
import { ReactiveVar } from 'meteor/reactive-var';
import { Mongo } from 'meteor/mongo';
import { Tracker } from 'meteor/tracker';
// Client-side collection mirror
export const CronJobStatus = new Mongo.Collection('cronJobStatus');
export const cronMigrationProgress = new ReactiveVar(0);
export const cronMigrationStatus = new ReactiveVar('');
export const cronMigrationCurrentStep = new ReactiveVar('');
export const cronMigrationSteps = new ReactiveVar([]);
export const cronIsMigrating = new ReactiveVar(false);
export const cronJobs = new ReactiveVar([]);
export const cronMigrationCurrentStepNum = new ReactiveVar(0);
export const cronMigrationTotalSteps = new ReactiveVar(0);
export const cronMigrationCurrentAction = new ReactiveVar('');
export const cronMigrationJobProgress = new ReactiveVar(0);
export const cronMigrationJobStepNum = new ReactiveVar(0);
export const cronMigrationJobTotalSteps = new ReactiveVar(0);
export const cronMigrationEtaSeconds = new ReactiveVar(null);
export const cronMigrationElapsedSeconds = new ReactiveVar(null);
export const cronMigrationCurrentNumber = new ReactiveVar(null);
export const cronMigrationCurrentName = new ReactiveVar('');
function fetchProgress() {
Meteor.call('cron.getMigrationProgress', (err, res) => {
if (err) return;
if (!res) return;
cronMigrationProgress.set(res.progress || 0);
cronMigrationStatus.set(res.status || '');
cronMigrationCurrentStep.set(res.currentStep || '');
cronMigrationSteps.set(res.steps || []);
cronIsMigrating.set(res.isMigrating || false);
cronMigrationCurrentStepNum.set(res.currentStepNum || 0);
cronMigrationTotalSteps.set(res.totalSteps || 0);
cronMigrationCurrentAction.set(res.currentAction || '');
cronMigrationJobProgress.set(res.jobProgress || 0);
cronMigrationJobStepNum.set(res.jobStepNum || 0);
cronMigrationJobTotalSteps.set(res.jobTotalSteps || 0);
cronMigrationEtaSeconds.set(res.etaSeconds ?? null);
cronMigrationElapsedSeconds.set(res.elapsedSeconds ?? null);
cronMigrationCurrentNumber.set(res.migrationNumber ?? null);
cronMigrationCurrentName.set(res.migrationName || '');
if ((!res.steps || res.steps.length === 0) && !res.isMigrating) {
const loaded = res.migrationStepsLoaded || 0;
const total = res.migrationStepsTotal || 0;
if (total > 0) {
cronMigrationStatus.set(
`Updating Select Migration dropdown menu (${loaded}/${total})`
);
} else {
cronMigrationStatus.set('Updating Select Migration dropdown menu');
}
}
});
}
if (Meteor.isClient) {
// Subscribe to migration status updates (real-time pub/sub)
Meteor.subscribe('cronMigrationStatus');
// Subscribe to cron jobs list (replaces polling cron.getJobs)
Meteor.subscribe('cronJobs');
// Subscribe to detailed migration progress data
Meteor.subscribe('migrationProgress');
// Reactively update cron jobs from published collection
Tracker.autorun(() => {
const jobDocs = CronJobStatus.find({}).fetch();
cronJobs.set(jobDocs);
});
// Reactively update status from published data
Tracker.autorun(() => {
const statusDoc = CronJobStatus.findOne({ jobId: 'migration' });
if (statusDoc) {
cronIsMigrating.set(statusDoc.status === 'running' || statusDoc.status === 'starting');
// Update status text based on job status
if (statusDoc.status === 'starting') {
cronMigrationStatus.set(statusDoc.statusMessage || 'Starting migrations...');
} else if (statusDoc.status === 'pausing') {
cronMigrationStatus.set(statusDoc.statusMessage || 'Pausing migrations...');
} else if (statusDoc.status === 'stopping') {
cronMigrationStatus.set(statusDoc.statusMessage || 'Stopping migrations...');
} else if (statusDoc.statusMessage) {
cronMigrationStatus.set(statusDoc.statusMessage);
}
if (statusDoc.progress !== undefined) {
cronMigrationJobProgress.set(statusDoc.progress);
}
}
});
// Reactively update job progress from migration details
Tracker.autorun(() => {
const runningJob = CronJobStatus.findOne(
{ status: 'running', jobType: 'migration' },
{ sort: { updatedAt: -1 } }
);
if (runningJob) {
cronMigrationJobProgress.set(runningJob.progress || 0);
// Get ETA information if available
if (runningJob.startedAt && runningJob.progress > 0) {
const elapsed = Math.round((Date.now() - runningJob.startedAt.getTime()) / 1000);
const eta = Math.round((elapsed * (100 - runningJob.progress)) / runningJob.progress);
cronMigrationEtaSeconds.set(eta);
cronMigrationElapsedSeconds.set(elapsed);
}
}
});
// Initial fetch for migration steps and other data
fetchProgress();
// Poll periodically only for migration steps dropdown (non-reactive data)
// Increased from 5000ms to 10000ms since most data is now reactive via pub/sub
Meteor.setInterval(() => {
fetchProgress();
}, 10000);
}
export default {
cronMigrationProgress,
cronMigrationStatus,
cronMigrationCurrentStep,
cronMigrationSteps,
cronIsMigrating,
cronJobs,
cronMigrationCurrentAction,
cronMigrationJobProgress,
cronMigrationJobStepNum,
cronMigrationJobTotalSteps,
cronMigrationEtaSeconds,
cronMigrationElapsedSeconds,
cronMigrationCurrentNumber,
cronMigrationCurrentName,
};