fix: more work on background tasks
This commit is contained in:
@@ -44,9 +44,10 @@ surface GenerationRuntimeSurface {
|
||||
-- "Generated" for a full render and "Rewrote" for a validation apply —
|
||||
-- and advances the bar by the number of URLs written.
|
||||
--
|
||||
-- Before section work begins, generation counts its planned URLs. The
|
||||
-- task reports 0/total immediately and advances once per rendered URL,
|
||||
-- matching bDS2's route-based generation progress.
|
||||
-- Route preparation and counting happen in background work before
|
||||
-- section rendering. Validation totals count only prepared URLs
|
||||
-- selected by the validation report, not the whole section. The task
|
||||
-- reports 0/total immediately and advances once per rendered URL.
|
||||
--
|
||||
-- Full generation and validation apply share the same structuring: a
|
||||
-- task group containing one task per section (Render Site Core, Render
|
||||
@@ -310,6 +311,9 @@ rule ApplyValidation {
|
||||
-- unchanged post route refreshes its tracked generation time so the
|
||||
-- automatic follow-up validation does not report it stale again.
|
||||
ensures: GenerateSiteRequested(plan_generation(project_id, sections))
|
||||
-- Observable phases are prepare, affected render sections, optional
|
||||
-- calendar regeneration, search indexing, and final validation. Failure or
|
||||
-- cancellation stops every dependent phase.
|
||||
}
|
||||
|
||||
-- Day-block grouping for archives
|
||||
|
||||
@@ -262,7 +262,9 @@ invariant PanelTabFallback {
|
||||
-- git_log unavailable when neither post nor media tab is active
|
||||
}
|
||||
|
||||
-- Tasks tab: last 10 tasks, newest first, with progress/cancel.
|
||||
-- Tasks tab: every active task plus the 10 newest finished tasks, with
|
||||
-- progress/cancel. Active groups always include every child needed to show a
|
||||
-- complete group even when this exceeds the finished-history limit.
|
||||
-- Tasks with shared group_id are collapsible groups showing bDS2-style
|
||||
-- average child progress; pending children contribute zero.
|
||||
-- Output tab: log entries with copy-all button.
|
||||
@@ -287,6 +289,12 @@ value StatusBarLeft {
|
||||
running_task_overflow: Integer? -- "+N more" count when multiple running
|
||||
}
|
||||
|
||||
invariant StatusBarTaskSelection {
|
||||
-- The indicator selects the first running task, otherwise the first
|
||||
-- pending task. Overflow counts every other running or pending task.
|
||||
-- Status remains typed until its display label is localized.
|
||||
}
|
||||
|
||||
value StatusBarRight {
|
||||
-- In display order (left to right):
|
||||
post_status: String? -- draft|published|archived dot, when post tab active
|
||||
|
||||
@@ -135,6 +135,11 @@ surface ScriptRuntimeSurface {
|
||||
-- sync_from_posts.
|
||||
-- bds.tasks: get, status_snapshot, cancel, get_all, get_running,
|
||||
-- clear_completed.
|
||||
-- get and get_all inspect every retained task rather than the
|
||||
-- status-snapshot history cap; get_all is newest first. get_running
|
||||
-- contains only running tasks. cancel succeeds only for a pending or
|
||||
-- running task. clear_completed removes completed tasks while keeping
|
||||
-- failed and cancelled results.
|
||||
-- bds.sync: check_availability, get_repo_state, get_status,
|
||||
-- get_history, get_remote_state, fetch, pull, push, commit_all.
|
||||
-- bds.publish: upload_site.
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
entity Task {
|
||||
name: String
|
||||
status: pending | running | completed | failed | cancelled
|
||||
source: local | remote
|
||||
cancellable: Boolean
|
||||
cancellation_requested: Boolean
|
||||
progress: Decimal? -- 0.0..1.0
|
||||
message: String?
|
||||
group_id: String? -- Optional task grouping
|
||||
@@ -28,6 +31,7 @@ surface TaskControlSurface {
|
||||
SubmitTaskRequested(name, work)
|
||||
CancelTaskRequested(task)
|
||||
RegisterExternalTaskRequested(name)
|
||||
TaskStateRequested()
|
||||
}
|
||||
|
||||
surface TaskRuntimeSurface {
|
||||
@@ -38,6 +42,8 @@ surface TaskRuntimeSurface {
|
||||
TaskWorkFailed(task, error_message)
|
||||
ProgressReported(task, value, message)
|
||||
FinishedTaskEvictionDue()
|
||||
WorkerCapacityAvailable()
|
||||
TaskWorkStopped(task)
|
||||
}
|
||||
|
||||
surface TaskSurface {
|
||||
@@ -46,6 +52,7 @@ surface TaskSurface {
|
||||
exposes:
|
||||
task.name
|
||||
task.status
|
||||
task.source
|
||||
task.progress when task.progress != null
|
||||
task.message when task.message != null
|
||||
task.group_id when task.group_id != null
|
||||
@@ -74,13 +81,23 @@ invariant FifoQueue {
|
||||
|
||||
rule SubmitTask {
|
||||
when: SubmitTaskRequested(name, work)
|
||||
let running_tasks = Tasks where status = running
|
||||
ensures:
|
||||
let task = Task.created(name: name, status: pending)
|
||||
let task = Task.created(
|
||||
name: name,
|
||||
status: pending,
|
||||
source: local,
|
||||
cancellable: true,
|
||||
cancellation_requested: false
|
||||
)
|
||||
task.status = pending
|
||||
if running_tasks.count < config.max_concurrent:
|
||||
task.status = running
|
||||
TaskStarted(task, work)
|
||||
}
|
||||
|
||||
rule StartNextTask {
|
||||
when: WorkerCapacityAvailable()
|
||||
let pending_tasks = Tasks where status = pending
|
||||
requires: pending_tasks.count > 0
|
||||
ensures: pending_tasks.first.status = running
|
||||
ensures: TaskStarted(pending_tasks.first)
|
||||
}
|
||||
|
||||
rule CompleteTask {
|
||||
@@ -99,8 +116,28 @@ rule FailTask {
|
||||
|
||||
rule CancelTask {
|
||||
when: CancelTaskRequested(task)
|
||||
requires: task.status = running or task.status = pending
|
||||
-- Cancellation uses a runtime-specific cancellation mechanism
|
||||
requires: task.status = pending
|
||||
ensures: task.status = cancelled
|
||||
ensures: NextQueuedTaskStarted()
|
||||
}
|
||||
|
||||
rule RequestRunningTaskCancellation {
|
||||
when: CancelTaskRequested(task)
|
||||
requires: task.status = running
|
||||
requires: task.cancellable
|
||||
ensures: task.cancellation_requested = true
|
||||
ensures: StopTaskWorkRequested(task)
|
||||
@guidance
|
||||
-- Long operations observe the request at phase or item boundaries.
|
||||
-- Owned child processes are terminated when the platform permits it.
|
||||
-- The task remains running and occupies its worker slot until work
|
||||
-- actually stops; status surfaces expose cancellation_requested.
|
||||
}
|
||||
|
||||
rule FinishRunningTaskCancellation {
|
||||
when: TaskWorkStopped(task)
|
||||
requires: task.status = running
|
||||
requires: task.cancellation_requested
|
||||
ensures: task.status = cancelled
|
||||
ensures: NextQueuedTaskStarted()
|
||||
}
|
||||
@@ -110,6 +147,9 @@ rule ReportProgress {
|
||||
-- Progress events throttled to 250ms
|
||||
ensures: task.progress = value
|
||||
ensures: task.message = message
|
||||
@guidance
|
||||
-- A report whose value is 1.0 is always accepted so the terminal
|
||||
-- localized phase text cannot be dropped by throttling.
|
||||
}
|
||||
|
||||
invariant ProgressThrottled {
|
||||
@@ -139,11 +179,24 @@ rule EvictFinishedTasks {
|
||||
ensures: not exists task
|
||||
}
|
||||
|
||||
rule PruneFinishedTasksOnAccess {
|
||||
when: TaskStateRequested()
|
||||
for task in Tasks where status in {completed, failed, cancelled}:
|
||||
if now - task.finished_at >= config.finished_task_ttl:
|
||||
ensures: not exists task
|
||||
}
|
||||
|
||||
-- External tasks: lifecycle controlled by caller (e.g., renderer-side scripts)
|
||||
rule RegisterExternalTask {
|
||||
when: RegisterExternalTaskRequested(name)
|
||||
ensures:
|
||||
let task = Task.created(name: name, status: running)
|
||||
let task = Task.created(
|
||||
name: name,
|
||||
status: running,
|
||||
source: remote,
|
||||
cancellable: true,
|
||||
cancellation_requested: false
|
||||
)
|
||||
task.status = running
|
||||
@guidance
|
||||
-- External tasks are not managed by the queue
|
||||
|
||||
Reference in New Issue
Block a user