Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eba7bff17a | |||
| 6ea6578acb |
@@ -89,8 +89,9 @@ flowchart LR
|
||||
`runner.RunJob` builds the platform-specific invocation, executes the
|
||||
command through the platform shell, captures stdout and stderr, writes one
|
||||
timestamped `.log` file, and returns a `domain.RunRecord` containing
|
||||
`DurationMS` (wall-clock milliseconds from start to finish; 0 for
|
||||
`StartOnly` fire-and-forget jobs).
|
||||
`DurationMS` (wall-clock milliseconds from start to finish; for `StartOnly`
|
||||
fire-and-forget jobs it measures launch latency — the time to spawn the
|
||||
process — since there is no exit to wait for).
|
||||
|
||||
6. History update:
|
||||
When a run goroutine completes, `Service` updates the job's runtime
|
||||
@@ -132,7 +133,7 @@ in flight increments `JobRuntime.PendingRuns`. When the current run finishes,
|
||||
|-------|---------|
|
||||
| `RunCount` | total runs recorded |
|
||||
| `FailCount` | runs that exited non-zero |
|
||||
| `LastDurationMS` | wall-clock time of the most recent run |
|
||||
| `LastDurationMS` | wall-clock time of the most recent run (launch latency for `StartOnly`) |
|
||||
| `AvgDurationMS` | mean over all runs with a recorded duration |
|
||||
| `MaxDurationMS` | longest recorded run |
|
||||
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
|
||||
All notable GoSentry changes are recorded in this file.
|
||||
|
||||
## 0.11.4 - 2026-06-30
|
||||
|
||||
**Statistics:**
|
||||
- `StartOnly` jobs now record launch latency (time to spawn the process) as the
|
||||
run duration instead of a hard-coded `0`, so the Statistics line shows a real
|
||||
last/avg/max for fire-and-forget jobs. Sub-millisecond launches still round to
|
||||
0 and are excluded from the average, as before.
|
||||
|
||||
## 0.11.3 - 2026-06-29
|
||||
|
||||
**Reliability fixes from an internal code review: safer runs, a real overlap
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@ package app
|
||||
// Version is the application version shown in the GUI and used by build
|
||||
// scripts in artifact names. It is a var rather than a const so release builds
|
||||
// can override it with Go ldflags when CI tags a build.
|
||||
var Version = "0.11.3"
|
||||
var Version = "0.11.4"
|
||||
|
||||
@@ -32,7 +32,9 @@ type JobRuntime struct {
|
||||
AvgDurationMS int64
|
||||
MaxDurationMS int64
|
||||
// TimedRunCount is the number of runs that contributed to AvgDurationMS.
|
||||
// StartOnly and legacy duration-less runs increment RunCount but not this.
|
||||
// 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
|
||||
}
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@ func RunJob(ctx context.Context, job *domain.Job, trigger string, logsDir string
|
||||
var durationMS int64
|
||||
if job.StartOnly {
|
||||
invocation := jobInvocation(ctx, *job)
|
||||
state, detail, output = startJobOnly(invocation, *job, started)
|
||||
// StartOnly jobs don't wait for process exit, so no meaningful duration.
|
||||
durationMS = 0
|
||||
// StartOnly jobs don't wait for process exit, so the duration measures
|
||||
// launch latency (time to spawn the process) rather than run time.
|
||||
state, detail, output, durationMS = startJobOnly(invocation, *job, started)
|
||||
} else {
|
||||
var stdoutBuf strings.Builder
|
||||
var stderrBuf strings.Builder
|
||||
@@ -72,21 +72,22 @@ func RunJob(ctx context.Context, job *domain.Job, trigger string, logsDir string
|
||||
}, logErr
|
||||
}
|
||||
|
||||
func startJobOnly(invocation commandInvocation, job domain.Job, started time.Time) (string, string, string) {
|
||||
func startJobOnly(invocation commandInvocation, job domain.Job, started time.Time) (string, string, string, int64) {
|
||||
command := invocation.command
|
||||
if invocation.hideWindow {
|
||||
winproc.ConfigureHiddenWindow(command)
|
||||
}
|
||||
err := command.Start()
|
||||
duration := time.Since(started).Round(time.Millisecond)
|
||||
durationMS := duration.Milliseconds()
|
||||
if err != nil {
|
||||
return "Failed", fmt.Sprintf("%T: %v", err, err), startOnlyOutput(job, 0)
|
||||
return "Failed", fmt.Sprintf("%T: %v", err, err), startOnlyOutput(job, 0), durationMS
|
||||
}
|
||||
pid := command.Process.Pid
|
||||
if releaseErr := command.Process.Release(); releaseErr != nil {
|
||||
return "Failed", fmt.Sprintf("process started with pid %d, but release failed: %T: %v", pid, releaseErr, releaseErr), startOnlyOutput(job, pid)
|
||||
return "Failed", fmt.Sprintf("process started with pid %d, but release failed: %T: %v", pid, releaseErr, releaseErr), startOnlyOutput(job, pid), durationMS
|
||||
}
|
||||
return "OK", fmt.Sprintf("Started in %s (pid %d); not waiting for process exit", duration, pid), startOnlyOutput(job, pid)
|
||||
return "OK", fmt.Sprintf("Started in %s (pid %d); not waiting for process exit", duration, pid), startOnlyOutput(job, pid), durationMS
|
||||
}
|
||||
|
||||
func startOnlyOutput(job domain.Job, pid int) string {
|
||||
|
||||
Reference in New Issue
Block a user