-
Notifications
You must be signed in to change notification settings - Fork 318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NAS-114805 / 22.12 / NAS-114805: Refactoring scheduler component #6440
Merged
Merged
Changes from 10 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
5f5ca92
NAS-114805: Refactoring CRON scheduler component
undsoft 4a99dbf
Merge branch 'master' of github.com:truenas/webui into NAS-114805
undsoft f5f0155
Merge branch 'master' of github.com:truenas/webui into NAS-114805
undsoft c203b38
NAS-114990: Debugging slow loading
undsoft ff9054b
Merge branch 'master' of github.com:truenas/webui into NAS-114990
undsoft 01bef66
NAS-114990: Limit number of completed jobs being loaded
undsoft 463f54b
NAS-114990: Limit number of completed jobs being loaded
undsoft f45c030
NAS-114990: Fix preferences not loading when no preferences are avail…
undsoft 6c944cf
Merge branch 'NAS-114990' into NAS-114805
undsoft d9cd822
NAS-114805: Bugfixes for form-scheduler
undsoft 8983c57
NAS-114805: Bugfixes for form-scheduler
undsoft 9aaee47
NAS-114805: Fixing tests
undsoft e888ae3
NAS-114805: Address PR comments
undsoft 4e9825a
NAS-114805: Address PR comments
undsoft File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,11 @@ | ||
export interface Schedule { | ||
// TODO: Check question marks | ||
minute?: string; | ||
hour?: string; | ||
dom?: string; | ||
month?: string; | ||
dow?: string; | ||
// TODO: May not belong here. | ||
begin?: string; | ||
end?: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
src/app/modules/scheduler/classes/cron-schedule-preview/cron-schedule-preview.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import Cron from 'croner'; | ||
import { | ||
addDays, | ||
endOfMonth, | ||
getDate, getMonth, isBefore, isWithinInterval, | ||
setHours, | ||
setMinutes, | ||
subMinutes, | ||
} from 'date-fns'; | ||
import { toDate, utcToZonedTime, zonedTimeToUtc } from 'date-fns-tz'; | ||
|
||
export interface CronSchedulerPreviewOptions { | ||
crontab: string; | ||
timezone: string; | ||
startTime?: string; | ||
endTime?: string; | ||
} | ||
|
||
export class CronSchedulePreview { | ||
private readonly cron: Cron; | ||
private readonly timezone: string; | ||
|
||
constructor(private options: CronSchedulerPreviewOptions) { | ||
this.timezone = this.options.timezone; | ||
this.cron = new Cron(this.options.crontab, { | ||
timezone: this.timezone, | ||
}); | ||
} | ||
|
||
/** | ||
* Returns next {limit} dates from startDate to the end of month. | ||
* startDate is specified in target timezone. | ||
* Returned dates are in local time, but stored in UTC (ordinary JS way). | ||
* @param startDate Starting date. | ||
* @param limit | ||
*/ | ||
listNextRunsInMonth(startDate: string, limit: number): Date[] { | ||
const nextRuns: Date[] = []; | ||
let previousDate: Date = this.getZonedStartDate(startDate); | ||
const zonedEndDate = this.getZoneEndDate(startDate); | ||
|
||
for (let i = 0; i < limit;) { | ||
const exampleDate = this.cron.next(previousDate); | ||
previousDate = exampleDate; | ||
|
||
if (!exampleDate || !isBefore(exampleDate, zonedEndDate)) { | ||
break; | ||
} | ||
|
||
if (!this.isWithinTimeConstrains(exampleDate)) { | ||
continue; | ||
} | ||
|
||
nextRuns.push(exampleDate); | ||
i = i + 1; | ||
} | ||
|
||
return nextRuns; | ||
} | ||
|
||
getNextDaysInMonthWithRuns(startDate: string): Set<number> { | ||
const monthDaysWithRuns = new Set<number>([]); | ||
|
||
let previousDate = toDate(startDate, { timeZone: 'UTC' }); | ||
const startingMonth = getMonth(previousDate); | ||
|
||
do { | ||
const zonedPreviousDate = zonedTimeToUtc(previousDate, this.timezone); | ||
const zonedNextRun = this.cron.next(subMinutes(zonedPreviousDate, 1)); | ||
const nextRun = utcToZonedTime(zonedNextRun, this.timezone); | ||
|
||
if (!nextRun || getMonth(nextRun) !== startingMonth) { | ||
break; | ||
} | ||
|
||
if (!this.isWithinTimeConstrains(nextRun)) { | ||
previousDate = nextRun; | ||
continue; | ||
} | ||
|
||
previousDate = addDays(previousDate, 1); | ||
|
||
const dayNumber = getDate(nextRun); | ||
monthDaysWithRuns.add(dayNumber); | ||
} while (getMonth(previousDate) === startingMonth); | ||
|
||
return monthDaysWithRuns; | ||
} | ||
|
||
private getZonedStartDate(forMonth: string): Date { | ||
const zonedForMonth = toDate(forMonth, { timeZone: this.timezone }); | ||
return subMinutes(zonedForMonth, 1); | ||
} | ||
|
||
private getZoneEndDate(forMonth: string): Date { | ||
const zonedForMonth = toDate(forMonth, { timeZone: 'UTC' }); | ||
const endDate = endOfMonth(zonedForMonth); | ||
return zonedTimeToUtc(endDate, this.timezone); | ||
} | ||
|
||
private isWithinTimeConstrains(date: Date): boolean { | ||
return true; | ||
// TODO: Will be implemented later. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why later? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because I got tired :) It's an edge case feature that I will address in coming PRs soon. |
||
if (!this.options.startTime || !this.options.endTime) { | ||
return true; | ||
} | ||
|
||
const [startHour, startMinutes] = this.options.startTime.split(':'); | ||
const [endHour, endMinutes] = this.options.endTime.split(':'); | ||
|
||
const startDate = setMinutes(setHours(date, Number(startHour)), Number(startMinutes)); | ||
const endDate = setMinutes(setHours(date, Number(endHour)), Number(endMinutes)); | ||
|
||
return isWithinInterval(date, { start: startDate, end: endDate }); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not have this in the for loop declaration?
for (let i = 0; i < limit; i++)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because there is a
continue
condition that doesn't actually need it.