18da021526
Phase 11 of PROJECT_REVIEW_PLAN.md: the themed cleanup pass over every low-severity finding still open (2.2-2.3, 3.4-3.6, 4.3-4.7, 6.4-6.7, 7.1-7.3, 8.2-8.3, 9.1-9.4, and the under-documented decisions in §10/§11). Behavioral fixes: - Reassign duplicate job IDs in a hand-edited jobs.json instead of letting two jobs share one runtime, schedule entry, and SeedStats bucket. - Disambiguate run-log file names that collide within the same second. - Compute AvgDurationMS as DurationSumMS/TimedRunCount instead of an incremental integer mean, so it always matches the seeded-from-logs average instead of drifting from truncation error. - Clean absolute paths in ResolveConfiguredPath so two spellings of the same jobs file do not trigger a spurious adoption. - Report InstallDesktopIcon failures through ErrorOccurred instead of discarding them silently. - Move settingsView's blocking AutostartStatus (PowerShell on Windows) off the UI thread. - Give notify-timing.tsv its own extension so CleanupLogs no longer manages it as a run log. - Replace the settingsView Save handler's second copy of validateConfig's rules with a bare parse, letting the Service's own error surface. Cleanups: - Delete collectActivity, the dead yaml tags on RunRecord, and the logArguments/LogArguments alias. - Fold the two systemTrayRegistered/mainWindowHidden globals into one trayState instance Run owns and threads through Settings and the single-instance reveal path. - Fix stale comments/docs: the frozen window-size restore claim, a reference to a renamed recordRun, README's "Pause all" and notification wording, the PowerShell quoting note for TESTS.md's coverage command, and scripts/test.bat's UTF-8 checkmarks under a non-UTF-8 code page. - Document the single-instance fallback's consequence and the unauthenticated instance-channel port in STANDARDS.md; record the config-shim retirement plan in ROADMAP.md. 3.5, 7.3, and 9.4 turned out to already be fixed by earlier phases; no change needed for those three. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
76 lines
2.8 KiB
Go
76 lines
2.8 KiB
Go
package domain
|
|
|
|
import "time"
|
|
|
|
// JobRuntime is the transient execution state for a Job. It is never written to
|
|
// jobs.json: it is rebuilt from scratch each time GoSentry starts and is held in
|
|
// memory keyed by Job.ID for the lifetime of the process. Keeping it separate
|
|
// from Job is what lets the durable configuration file stay free of run records,
|
|
// status strings, and scheduling bookkeeping.
|
|
type JobRuntime struct {
|
|
LastRun string
|
|
NextRun string
|
|
LastState string
|
|
Output string
|
|
Logs []RunRecord
|
|
|
|
// NextDue is the next scheduled execution time, kept as time.Time for
|
|
// scheduler comparisons. NextRun above is its formatted display string and is
|
|
// the only form shown in the GUI.
|
|
NextDue time.Time
|
|
|
|
// PendingRuns counts scheduled occurrences that fired while a run was still
|
|
// in flight under the "queue" overlap policy. executeRun drains the counter
|
|
// by starting one deferred run after each completion.
|
|
PendingRuns int
|
|
|
|
// Execution-time statistics accumulated since the last process start.
|
|
// Seeded from log files on startup; zero until then.
|
|
RunCount int
|
|
FailCount int
|
|
LastDurationMS int64
|
|
AvgDurationMS int64
|
|
MaxDurationMS int64
|
|
// TimedRunCount is the number of runs that contributed to AvgDurationMS.
|
|
// Runs with no recorded duration (legacy logs, or sub-millisecond StartOnly
|
|
// launches that round to 0) increment RunCount but not this. StartOnly runs
|
|
// otherwise contribute their launch latency.
|
|
TimedRunCount int
|
|
// DurationSumMS is the running total of every timed run's duration.
|
|
// AvgDurationMS is always DurationSumMS/TimedRunCount, computed fresh on each
|
|
// update rather than folded incrementally — an incremental integer mean
|
|
// truncates on every step, and the error compounds over the life of a job
|
|
// that keeps running. A stored sum divided once per update matches the exact
|
|
// sum/count average runner.aggregateLogStats computes when seeding from logs,
|
|
// so the two no longer disagree about the same run history.
|
|
DurationSumMS int64
|
|
}
|
|
|
|
// NewRuntime builds the initial runtime state for a freshly loaded or created
|
|
// job. Enabled jobs start "Ready" and wait for the scheduler to compute their
|
|
// first run; disabled jobs start "Paused".
|
|
func NewRuntime(job Job) *JobRuntime {
|
|
runtime := &JobRuntime{
|
|
LastRun: "Never",
|
|
Output: "No command output captured yet.",
|
|
}
|
|
if job.Enabled {
|
|
runtime.LastState = "Ready"
|
|
runtime.NextRun = "After start"
|
|
} else {
|
|
runtime.LastState = "Paused"
|
|
runtime.NextRun = "Paused"
|
|
}
|
|
return runtime
|
|
}
|
|
|
|
// NewRuntimes builds a runtime map for a slice of jobs, keyed by Job.ID. It is
|
|
// the convenience entry point used when a whole jobs file has just been loaded.
|
|
func NewRuntimes(jobs []Job) map[int]*JobRuntime {
|
|
runtimes := make(map[int]*JobRuntime, len(jobs))
|
|
for _, job := range jobs {
|
|
runtimes[job.ID] = NewRuntime(job)
|
|
}
|
|
return runtimes
|
|
}
|