feat: verify bounded simultaneous schedule execution
This commit is contained in:
111
sdk/go/cmd/orbit-schedule-load/report.go
Normal file
111
sdk/go/cmd/orbit-schedule-load/report.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
orbit "git.yuntuo.hk/k2safe/orbit/sdk/go"
|
||||
"math"
|
||||
"runtime"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
||||
// distribution 仅统计已逐项核验的任务;空集合百分位为null,单位毫秒。
|
||||
type distribution struct {
|
||||
Count int `json:"count"` // Count 统计分母。
|
||||
P50 *float64 `json:"p50_ms"` // P50 最近秩中位数。
|
||||
P95 *float64 `json:"p95_ms"` // P95 最近秩95百分位。
|
||||
P99 *float64 `json:"p99_ms"` // P99 最近秩99百分位。
|
||||
Max *float64 `json:"max_ms"` // Max 最大耗时。
|
||||
}
|
||||
|
||||
// planReport 保存原操作身份;请求结果不明时只能按原键和原请求核查。
|
||||
type planReport struct {
|
||||
CalendarVersion string `json:"calendar_version,omitempty"` // CalendarVersion 创建回执中的时区快照标识,后续读取不得变化。
|
||||
EffectiveAt time.Time `json:"effective_at"` // EffectiveAt 固定计划版本生效时间。
|
||||
Index int `json:"index"` // Index 从零开始的计划序号。
|
||||
ID string `json:"id,omitempty"` // ID 已取得的计划身份;空不证明创建未提交。
|
||||
CreateKey string `json:"create_key"` // CreateKey 创建键,同时作为计划名称。
|
||||
ResumeKey string `json:"resume_key,omitempty"` // ResumeKey 原恢复键。
|
||||
ResumeRevision uint64 `json:"resume_revision,string"` // ResumeRevision 原恢复请求版本,零表示尚未发送。
|
||||
Resumed bool `json:"resumed"` // Resumed 已收到且核对恢复回执。
|
||||
Exhausted bool `json:"exhausted"` // Exhausted 已观察到固定版本无下个触发点和扫描工作。
|
||||
PauseKey string `json:"pause_key,omitempty"` // PauseKey 最后发送的暂停键,仅明确版本冲突才换键。
|
||||
PauseRevision uint64 `json:"pause_revision,string"` // PauseRevision 最后暂停请求的预期版本。
|
||||
PauseConfirmed bool `json:"pause_confirmed"` // PauseConfirmed 已确认计划暂停;不取消已生成任务。
|
||||
Occurrences int `json:"occurrences"` // Occurrences 已观察唯一触发点数。
|
||||
Fired int `json:"fired"` // Fired 已关联唯一任务的单点触发数。
|
||||
VerifiedSuccess int `json:"verified_success"` // VerifiedSuccess 完成任务/尝试/来源核对数。
|
||||
}
|
||||
|
||||
// scheduleReport 是隔离环境有界样本,不作为生产容量或高可用承诺。
|
||||
type scheduleReport struct {
|
||||
RunID string `json:"run_id"` // RunID 计划、处理器和操作键的隔离身份。
|
||||
GoVersion string `json:"go_version"` // GoVersion 实际编译工具链。
|
||||
GOOS string `json:"goos"` // GOOS 运行系统。
|
||||
GOARCH string `json:"goarch"` // GOARCH 运行架构。
|
||||
StartedAt time.Time `json:"started_at"` // StartedAt 预检开始本机时间。
|
||||
FinishedAt time.Time `json:"finished_at"` // FinishedAt 全部有界收尾完成本机时间。
|
||||
Requests int `json:"requests_per_schedule"` // Requests 每计划预期触发数。
|
||||
Schedules int `json:"schedules"` // Schedules 预期计划数。
|
||||
Expected int `json:"expected_occurrences"` // Expected 总计划触发数,包含未观察的触发点。
|
||||
Workers int `json:"workers"` // Workers 本进程独立WSS Worker数。
|
||||
Capacity int `json:"capacity_per_worker"` // Capacity 每Worker并行槽数。
|
||||
IntervalMS int64 `json:"interval_ms"` // IntervalMS 固定间隔毫秒。
|
||||
StartDelayMS int64 `json:"start_delay_ms"` // StartDelayMS 创建/恢复的预留时间毫秒。
|
||||
RunTimeoutMS int64 `json:"run_timeout_ms"` // RunTimeoutMS 整个测量截止毫秒。
|
||||
PollIntervalMS int64 `json:"poll_interval_ms"` // PollIntervalMS 历史查询间隔毫秒。
|
||||
HTTPTimeoutMS int64 `json:"http_timeout_ms"` // HTTPTimeoutMS 每HTTP请求截止毫秒。
|
||||
Queue *orbit.Queue `json:"queue,omitempty"` // Queue 预检队列快照,只读配置。
|
||||
ScheduleStart time.Time `json:"schedule_start"` // ScheduleStart 所有计划共同起点,包含边界。
|
||||
ScheduleEnd time.Time `json:"schedule_end"` // ScheduleEnd 所有计划共同截止,排除边界。
|
||||
Plans []planReport `json:"plans"` // Plans 已尝试创建的固定身份和收尾证据。
|
||||
Occurrences int `json:"occurrences"` // Occurrences 已观察唯一触发数。
|
||||
Fired int `json:"fired"` // Fired 单点生成且关联唯一任务数,不代表成功。
|
||||
VerifiedSuccess int `json:"verified_success"` // VerifiedSuccess 持久化结果/唯一尝试/来源全部通过数。
|
||||
Unobserved int `json:"unobserved"` // Unobserved 预期但未观察到的触发点数。
|
||||
Unverified int `json:"unverified"` // Unverified 已触发但未核验成功的任务数。
|
||||
HandlerCalls int `json:"handler_calls"` // HandlerCalls 通过输入核对的处理器调用总数。
|
||||
DuplicateInvocations int `json:"duplicate_invocations"` // DuplicateInvocations 同一任务的额外调用数。
|
||||
UnconfirmedInvocations int `json:"unconfirmed_invocations"` // UnconfirmedInvocations 未对应到已核验任务及尝试的调用数。
|
||||
WorkerStarted uint64 `json:"worker_started"` // WorkerStarted SDK实际调用处理器数。
|
||||
Reconnects uint64 `json:"worker_reconnects"` // Reconnects SDK连接重建次数。
|
||||
Renewals uint64 `json:"worker_renewals_confirmed"` // Renewals 已确认租约续期次数。
|
||||
TriggerLag distribution `json:"trigger_lag"` // TriggerLag 计划时间至任务受理数据库耗时。
|
||||
QueueWait distribution `json:"queue_wait"` // QueueWait 任务受理至开始授权数据库耗时。
|
||||
Execution distribution `json:"authorized_execution"` // Execution 授权至结果落库耗时,包含网络和事务。
|
||||
Completion distribution `json:"completion"` // Completion 计划时间至结果落库耗时。
|
||||
Errors map[string]int `json:"errors"` // Errors 有限分类,不含凭据或原异常正文。
|
||||
Complete bool `json:"complete"` // Complete 全部计数、证据和收尾满足时为真。
|
||||
}
|
||||
|
||||
func newReport(c config, runID string) scheduleReport {
|
||||
return scheduleReport{RunID: runID, GoVersion: runtime.Version(), GOOS: runtime.GOOS, GOARCH: runtime.GOARCH, StartedAt: time.Now().UTC(), Requests: c.Requests, Schedules: c.Schedules, Expected: c.Requests * c.Schedules, Workers: c.Workers, Capacity: c.Capacity, IntervalMS: c.Interval.Milliseconds(), StartDelayMS: c.StartDelay.Milliseconds(), RunTimeoutMS: c.RunTimeout.Milliseconds(), PollIntervalMS: c.PollInterval.Milliseconds(), HTTPTimeoutMS: c.Timeout.Milliseconds(), Plans: []planReport{}, Errors: map[string]int{}}
|
||||
}
|
||||
func (r scheduleReport) finish() scheduleReport {
|
||||
for code, n := range r.Errors {
|
||||
if n == 0 {
|
||||
delete(r.Errors, code)
|
||||
}
|
||||
}
|
||||
r.FinishedAt = time.Now().UTC()
|
||||
r.Unobserved = r.Expected - r.Occurrences
|
||||
r.Unverified = r.Fired - r.VerifiedSuccess
|
||||
plansReady := len(r.Plans) == r.Schedules
|
||||
for _, p := range r.Plans {
|
||||
plansReady = plansReady && p.Resumed && p.Exhausted && p.PauseConfirmed && p.VerifiedSuccess == r.Requests
|
||||
}
|
||||
r.Complete = r.Expected > 0 && plansReady && r.Occurrences == r.Expected && r.Fired == r.Expected && r.VerifiedSuccess == r.Expected && r.HandlerCalls == r.Expected && r.WorkerStarted == uint64(r.Expected) && r.DuplicateInvocations == 0 && r.UnconfirmedInvocations == 0 && len(r.Errors) == 0
|
||||
return r
|
||||
}
|
||||
func distributionOf(values []time.Duration) distribution {
|
||||
d := distribution{Count: len(values)}
|
||||
if len(values) == 0 {
|
||||
return d
|
||||
}
|
||||
sort.Slice(values, func(i, j int) bool { return values[i] < values[j] })
|
||||
percentile := func(q float64) *float64 {
|
||||
v := float64(values[int(math.Ceil(float64(len(values))*q))-1]) / float64(time.Millisecond)
|
||||
return &v
|
||||
}
|
||||
d.P50, d.P95, d.P99, d.Max = percentile(.5), percentile(.95), percentile(.99), percentile(1)
|
||||
return d
|
||||
}
|
||||
Reference in New Issue
Block a user