Skip to content

Commit

Permalink
Async execution improvements (#12282)
Browse files Browse the repository at this point in the history
- Close enso-org/cloud-v2#1739
- Invalidate executions periodically (every minute) to make sure they are up to date
- Fix path for deleting project executions
- Use ISO dates for all dates - including the date input
- Fix not being able to edit dates
- Add combo box for selecting timezone
- Hide selected option in dropdown so that it does not show up twice
- Completely hide advanced options (execution time limit, parallel mode) by default
- Rename "X of month" to "Monthly on X"
- Change "daily" repeat type to mean every day
- Add "weekly" repeat type
- Remove "hourly" repeat type
- Show count of executions per day in calendar cells instead of list of times
- Only show three next repeat dates, and move to end
- ⚠️ Not yet using the new endpoint yet to fetch execution status

# Important Notes
None
  • Loading branch information
somebody1234 authored Feb 27, 2025
1 parent d688c38 commit fb690e6
Show file tree
Hide file tree
Showing 48 changed files with 2,063 additions and 844 deletions.
1 change: 1 addition & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ test --test_output=errors
build --show_result=20
build --reuse_sandbox_directories
build --nolegacy_external_runfiles
build --incompatible_strict_action_env
build --noexperimental_check_output_files --experimental_allow_tags_propagation
fetch --noexperimental_check_output_files --experimental_allow_tags_propagation
query --noexperimental_check_output_files --experimental_allow_tags_propagation
Expand Down
2 changes: 1 addition & 1 deletion MODULE.bazel.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@tanstack/vue-query": "5.59.20"
},
"dependencies": {
"@internationalized/date": "3.7.0",
"@tanstack/query-persist-client-core": "5.59.20",
"@tanstack/vue-query": "5.59.20",
"@types/node": "^20.11.21",
Expand Down
51 changes: 28 additions & 23 deletions app/common/src/services/Backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,20 +381,20 @@ export type ProjectParallelMode = (typeof PROJECT_PARALLEL_MODES)[number]

export const PROJECT_EXECUTION_REPEAT_TYPES = [
'none',
'hourly',
'daily',
'monthly-date',
'monthly-weekday',
'monthly-last-weekday',
'weekly',
'monthlyDate',
'monthlyWeekday',
'monthlyLastWeekday',
] as const

export const PROJECT_EXECUTION_REPEAT_TYPE_TO_TEXT_ID = {
none: 'noneProjectExecutionRepeatType',
hourly: 'hourlyProjectExecutionRepeatType',
daily: 'dailyProjectExecutionRepeatType',
'monthly-date': 'monthlyProjectExecutionRepeatType',
'monthly-weekday': 'monthlyProjectExecutionRepeatType',
'monthly-last-weekday': 'monthlyProjectExecutionRepeatType',
weekly: 'weeklyProjectExecutionRepeatType',
monthlyDate: 'monthlyProjectExecutionRepeatType',
monthlyWeekday: 'monthlyProjectExecutionRepeatType',
monthlyLastWeekday: 'monthlyProjectExecutionRepeatType',
} satisfies {
readonly [K in ProjectExecutionRepeatType]: TextId & `${string}ProjectExecutionRepeatType`
}
Expand All @@ -407,22 +407,20 @@ export interface ProjectExecutionNoneRepeatInfo {
readonly type: 'none'
}

/** Details for a project execution that repeats hourly. */
export interface ProjectExecutionHourlyRepeatInfo {
readonly type: 'hourly'
readonly startHour: number
readonly endHour: number
}

/** Details for a project execution that repeats daily. */
export interface ProjectExecutionDailyRepeatInfo {
readonly type: 'daily'
}

/** Details for a project execution that repeats weekly on one or more days. */
export interface ProjectExecutionWeeklyRepeatInfo {
readonly type: 'weekly'
readonly daysOfWeek: readonly number[]
}

/** Details for a project execution that repeats monthly on a specific date. */
export interface ProjectExecutionMonthlyDateRepeatInfo {
readonly type: 'monthly-date'
readonly type: 'monthlyDate'
readonly date: number
readonly months: readonly number[]
}
Expand All @@ -432,7 +430,7 @@ export interface ProjectExecutionMonthlyDateRepeatInfo {
* of a specific month.
*/
export interface ProjectExecutionMonthlyWeekdayRepeatInfo {
readonly type: 'monthly-weekday'
readonly type: 'monthlyWeekday'
readonly weekNumber: number
readonly dayOfWeek: number
readonly months: readonly number[]
Expand All @@ -443,14 +441,14 @@ export interface ProjectExecutionMonthlyWeekdayRepeatInfo {
* of a specific month.
*/
export interface ProjectExecutionMonthlyLastWeekdayRepeatInfo {
readonly type: 'monthly-last-weekday'
readonly type: 'monthlyLastWeekday'
readonly dayOfWeek: number
readonly months: readonly number[]
}

export type ProjectExecutionRepeatInfo =
| ProjectExecutionHourlyRepeatInfo
| ProjectExecutionDailyRepeatInfo
| ProjectExecutionWeeklyRepeatInfo
| ProjectExecutionMonthlyDateRepeatInfo
| ProjectExecutionMonthlyWeekdayRepeatInfo
| ProjectExecutionMonthlyLastWeekdayRepeatInfo
Expand All @@ -459,18 +457,21 @@ export type ProjectExecutionRepeatInfo =
/** Metadata for a {@link ProjectExecution}. */
export interface ProjectExecutionInfo {
readonly projectId: ProjectId
readonly timeZone: string
readonly repeat: ProjectExecutionRepeatInfo
readonly parallelMode: ProjectParallelMode
readonly maxDurationMinutes: number
readonly startDate: dateTime.Rfc3339DateTime
readonly endDate: dateTime.Rfc3339DateTime | null
readonly timeZone: dateTime.IanaTimeZone
readonly maxDurationMinutes: number
readonly parallelMode: ProjectParallelMode
}

/** A specific execution schedule of a project. */
export interface ProjectExecution extends ProjectExecutionInfo {
readonly enabled: boolean
readonly executionId: ProjectExecutionId
readonly organizationId: OrganizationId
readonly versionId: S3ObjectVersionId
readonly nextExecution: dateTime.Rfc3339DateTime
readonly projectSessions?: readonly ProjectSession[]
}

/** Metadata describing the location of an uploaded file. */
Expand Down Expand Up @@ -1824,6 +1825,10 @@ export default abstract class Backend {
body: CreateProjectExecutionRequestBody,
title: string,
): Promise<ProjectExecution>
abstract getProjectExecutionDetails(
executionId: ProjectExecutionId,
title: string,
): Promise<ProjectExecution>
abstract updateProjectExecution(
executionId: ProjectExecutionId,
body: UpdateProjectExecutionRequestBody,
Expand Down
105 changes: 37 additions & 68 deletions app/common/src/services/Backend/__test__/projectExecution.test.ts
Original file line number Diff line number Diff line change
@@ -1,100 +1,69 @@
import { ZonedDateTime } from '@internationalized/date'
import * as v from 'vitest'
import { toRfc3339 } from '../../../utilities/data/dateTime'
import { IanaTimeZone, toRfc3339 } from '../../../utilities/data/dateTime'
import { ProjectExecutionInfo, ProjectId } from '../../Backend'
import { firstProjectExecutionOnOrAfter, nextProjectExecutionDate } from '../projectExecution'

const HOURLY_EXECUTION_1: ProjectExecutionInfo = {
projectId: ProjectId('project-aaaaaaaa'),
repeat: {
type: 'hourly',
startHour: 7,
endHour: 15,
},
startDate: toRfc3339(new Date(2020, 0, 1, 10, 59)),
timeZone: 'UTC',
maxDurationMinutes: 60,
parallelMode: 'ignore',
}
const TIME_ZONE = 'America/Los_Angeles'
const TIME_ZONE_WINTER_OFFSET = -28800000
const TIME_ZONE_SUMMER_OFFSET = -25200000

const HOURLY_EXECUTION_2: ProjectExecutionInfo = {
const WEEKLY_EXECUTION: ProjectExecutionInfo = {
projectId: ProjectId('project-aaaaaaaa'),
repeat: {
type: 'hourly',
startHour: 20,
endHour: 4,
},
startDate: toRfc3339(new Date(2015, 2, 8, 22, 33)),
timeZone: 'UTC',
maxDurationMinutes: 60,
parallelMode: 'ignore',
}

const DAILY_EXECUTION: ProjectExecutionInfo = {
projectId: ProjectId('project-aaaaaaaa'),
repeat: {
type: 'daily',
type: 'weekly',
daysOfWeek: [0, 5],
},
startDate: toRfc3339(new Date(2000, 0, 1, 7, 3)),
timeZone: 'UTC',
startDate: toRfc3339(
new ZonedDateTime(2000, 1, 1, TIME_ZONE, TIME_ZONE_WINTER_OFFSET, 7, 3).toDate(),
),
endDate: null,
timeZone: IanaTimeZone('UTC'),
maxDurationMinutes: 60,
parallelMode: 'ignore',
}

v.test.each([
{
info: DAILY_EXECUTION,
current: new Date(2000, 5, 4, 7, 3),
next1: new Date(2000, 5, 9, 7, 3),
next2: new Date(2000, 5, 11, 7, 3),
next3: new Date(2000, 5, 16, 7, 3),
},
{
info: HOURLY_EXECUTION_1,
current: new Date(2022, 10, 21, 14, 59),
next1: new Date(2022, 10, 21, 15, 59),
next2: new Date(2022, 10, 22, 7, 59),
next3: new Date(2022, 10, 22, 8, 59),
},
{
info: HOURLY_EXECUTION_2,
current: new Date(2018, 4, 11, 3, 33),
next1: new Date(2018, 4, 11, 4, 33),
next2: new Date(2018, 4, 11, 20, 33),
next3: new Date(2018, 4, 11, 21, 33),
},
{
info: HOURLY_EXECUTION_2,
current: new Date(2018, 4, 11, 23, 33),
next1: new Date(2018, 4, 12, 0, 33),
next2: new Date(2018, 4, 12, 1, 33),
next3: new Date(2018, 4, 12, 2, 33),
info: WEEKLY_EXECUTION,
current: new ZonedDateTime(2000, 6, 4, TIME_ZONE, TIME_ZONE_SUMMER_OFFSET, 7, 3),
next1: new ZonedDateTime(2000, 6, 9, TIME_ZONE, TIME_ZONE_SUMMER_OFFSET, 7, 3),
next2: new ZonedDateTime(2000, 6, 11, TIME_ZONE, TIME_ZONE_SUMMER_OFFSET, 7, 3),
next3: new ZonedDateTime(2000, 6, 16, TIME_ZONE, TIME_ZONE_SUMMER_OFFSET, 7, 3),
},
] satisfies readonly {
info: ProjectExecutionInfo
current: Date
next1: Date
next2: Date
next3: Date
current: ZonedDateTime
next1: ZonedDateTime
next2: ZonedDateTime
next3: ZonedDateTime
}[])(
'Get next project execution date (current: $current)',
({ info, current, next1, next2, next3 }) => {
v.expect(nextProjectExecutionDate(info, current)).toStrictEqual(next1)
v.expect(nextProjectExecutionDate(info, next1)).toStrictEqual(next2)
v.expect(nextProjectExecutionDate(info, next2)).toStrictEqual(next3)
v.expect(nextProjectExecutionDate(info, current)?.toString()).toBe(next1.toString())
v.expect(nextProjectExecutionDate(info, next1)?.toString()).toBe(next2.toString())
v.expect(nextProjectExecutionDate(info, next2)?.toString()).toBe(next3.toString())
},
)

v.test.each([
{ info: DAILY_EXECUTION, current: new Date(1999, 1, 1), next: new Date(2000, 0, 2, 7, 3) },
{ info: DAILY_EXECUTION, current: new Date(2000, 10, 16), next: new Date(2000, 10, 17, 7, 3) },
{
info: WEEKLY_EXECUTION,
current: new ZonedDateTime(1999, 1, 1, TIME_ZONE, TIME_ZONE_WINTER_OFFSET),
next: new ZonedDateTime(2000, 1, 2, TIME_ZONE, TIME_ZONE_WINTER_OFFSET, 7, 3),
},
{
info: WEEKLY_EXECUTION,
current: new ZonedDateTime(2000, 11, 16, TIME_ZONE, TIME_ZONE_WINTER_OFFSET),
next: new ZonedDateTime(2000, 11, 17, TIME_ZONE, TIME_ZONE_WINTER_OFFSET, 7, 3),
},
] satisfies readonly {
info: ProjectExecutionInfo
current: Date
next: Date
current: ZonedDateTime
next: ZonedDateTime
}[])(
'Get first project execution date on or after (current: $current)',
({ info, current, next }) => {
v.expect(firstProjectExecutionOnOrAfter(info, current)).toStrictEqual(next)
v.expect(firstProjectExecutionOnOrAfter(info, current).toString()).toBe(next.toString())
},
)
Loading

0 comments on commit fb690e6

Please sign in to comment.