package main import ( "math" "runtime" "sort" "time" orbit "git.yuntuo.hk/k2safe/orbit/sdk/go" ) // 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 纳入样本的最大毫秒数。 } // instanceReport 保存每个启动请求的原身份,便于未知结果按原键核对。 type instanceReport struct { Sequence int `json:"sequence"` // Sequence 从零开始的请求序号。 Key string `json:"key"` // Key 启动幂等键,同时作为业务键。 ID string `json:"id,omitempty"` // ID 已取得的实例身份;为空不证明未提交。 Code string `json:"admission_error,omitempty"` // Code 受理错误分类,不包含原异常正文。 Verified bool `json:"verified"` // Verified 是否通过持久结果核验。 } // workflowReport 是一次有界流程测量结果,不是容量承诺或生产高可用验收。 type workflowReport struct { Instances []instanceReport `json:"instances"` // Instances 已尝试启动的请求身份,包含失败或未知结果。 UnconfirmedInvocations int `json:"unconfirmed_invocations"` // UnconfirmedInvocations 尚未关联到已核验分支任务/尝试的调用数。 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 从预检开始的本机时间。 AdmissionFinishedAt time.Time `json:"admission_finished_at"` // AdmissionFinishedAt 实例受理组完成时间。 FinishedAt time.Time `json:"finished_at"` // FinishedAt 核验及Worker收尾完成时间。 Requests int `json:"requests"` // Requests 计划启动的流程实例数。 Concurrency int `json:"concurrency"` // Concurrency 启动和核验请求的最大并发。 Workers int `json:"workers"` // Workers 本进程独立WSS Worker数。 Capacity int `json:"capacity_per_worker"` // Capacity 每个Worker的执行槽上限。 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 预检时的队列快照,不修改配置。 DefinitionID string `json:"definition_id,omitempty"` // DefinitionID 本次新建的稳定定义身份。 VersionID string `json:"version_id,omitempty"` // VersionID 本次发布的不可变版本身份。 Attempted int `json:"attempted"` // Attempted 实际发起的启动调用数。 NotSubmitted int `json:"not_submitted"` // NotSubmitted 截止前未发起的实例数。 Accepted int `json:"accepted"` // Accepted 收到并核验唯一启动回执的实例数。 AdmissionErrors int `json:"admission_errors"` // AdmissionErrors 明确拒绝或回执不合法的实例数。 VerifiedSuccess int `json:"verified_success"` // VerifiedSuccess 流程、步骤、任务、来源和结果均核验通过数。 Unverified int `json:"unverified"` // Unverified 已受理但没有完成全部核验的实例数。 HandlerCalls int `json:"handler_calls"` // HandlerCalls 有效处理器调用总数,两个分支各一次。 DuplicateInvocations int `json:"duplicate_invocations"` // DuplicateInvocations 同一任务的额外调用数,不能抵充另一分支。 WorkerStarted uint64 `json:"worker_started"` // WorkerStarted SDK本进程领取并启动的任务数。 Reconnects uint64 `json:"worker_reconnects"` // Reconnects SDK重连次数。 Renewals uint64 `json:"worker_renewals_confirmed"` // Renewals SDK确认的租约续期次数。 Admission distribution `json:"admission"` // Admission 启动请求本机往返耗时。 Completion distribution `json:"completion"` // Completion 数据库实例创建至完成的服务端耗时。 Errors map[string]int `json:"errors"` // Errors 稳定错误分类,不写入凭据、SQL或请求正文。 Complete bool `json:"complete"` // Complete 仅全部实例和两倍处理器调用逐项通过核验时为真。 } func newReport(cfg config, runID string) workflowReport { return workflowReport{Instances: []instanceReport{}, RunID: runID, GoVersion: runtime.Version(), GOOS: runtime.GOOS, GOARCH: runtime.GOARCH, StartedAt: time.Now().UTC(), Requests: cfg.Requests, NotSubmitted: cfg.Requests, Concurrency: cfg.Concurrency, Workers: cfg.Workers, Capacity: cfg.Capacity, RunTimeoutMS: cfg.RunTimeout.Milliseconds(), PollIntervalMS: cfg.PollInterval.Milliseconds(), HTTPTimeoutMS: cfg.Timeout.Milliseconds(), Errors: map[string]int{}} } func (r workflowReport) finish() workflowReport { for code, count := range r.Errors { if count == 0 { delete(r.Errors, code) } } r.FinishedAt = time.Now().UTC() r.Unverified = r.Accepted - r.VerifiedSuccess r.Complete = r.Attempted == r.Requests && r.NotSubmitted == 0 && r.AdmissionErrors == 0 && r.Accepted == r.Requests && r.VerifiedSuccess == r.Requests && r.HandlerCalls == 2*r.Requests && r.WorkerStarted == uint64(2*r.Requests) && 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 }