feat: add read-only retention inventory
This commit is contained in:
@@ -23,17 +23,19 @@ func main() {
|
|||||||
}
|
}
|
||||||
func run() error {
|
func run() error {
|
||||||
if len(os.Args) < 2 {
|
if len(os.Args) < 2 {
|
||||||
return errors.New("usage: orbit-admin bootstrap|verify|credential status|rotate|revoke|apply")
|
return errors.New("usage: orbit-admin bootstrap|verify|retention inventory|credential status|rotate|revoke|apply")
|
||||||
}
|
}
|
||||||
switch os.Args[1] {
|
switch os.Args[1] {
|
||||||
case "bootstrap":
|
case "bootstrap":
|
||||||
return runBootstrap(os.Args[2:])
|
return runBootstrap(os.Args[2:])
|
||||||
case "verify":
|
case "verify":
|
||||||
return runVerify(os.Args[2:])
|
return runVerify(os.Args[2:])
|
||||||
|
case "retention":
|
||||||
|
return runRetention(os.Args[2:])
|
||||||
case "credential":
|
case "credential":
|
||||||
return runCredential(os.Args[2:])
|
return runCredential(os.Args[2:])
|
||||||
}
|
}
|
||||||
return errors.New("usage: orbit-admin bootstrap|verify|credential status|rotate|revoke|apply")
|
return errors.New("usage: orbit-admin bootstrap|verify|retention inventory|credential status|rotate|revoke|apply")
|
||||||
}
|
}
|
||||||
|
|
||||||
func runVerify(args []string) error {
|
func runVerify(args []string) error {
|
||||||
@@ -67,6 +69,43 @@ func runVerify(args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runRetention(args []string) error {
|
||||||
|
if len(args) == 0 || args[0] != "inventory" {
|
||||||
|
return errors.New("usage: orbit-admin retention inventory --before RFC3339")
|
||||||
|
}
|
||||||
|
flags := flag.NewFlagSet("retention inventory", flag.ContinueOnError)
|
||||||
|
var before string
|
||||||
|
flags.StringVar(&before, "before", "", "UTC cutoff; only records strictly before it are counted")
|
||||||
|
if err := flags.Parse(args[1:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if flags.NArg() != 0 || before == "" {
|
||||||
|
return errors.New("--before RFC3339 is required")
|
||||||
|
}
|
||||||
|
cutoff, err := time.Parse(time.RFC3339Nano, before)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("--before must be RFC3339")
|
||||||
|
}
|
||||||
|
cfg, err := config.Load()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
db, err := mysql.Open(ctx, cfg.MySQLDSN, 2, 1)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("database unavailable")
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
inventory, err := mysql.ReadRetentionInventory(ctx, db, cutoff)
|
||||||
|
encoded, encodeErr := json.Marshal(inventory)
|
||||||
|
if encodeErr != nil {
|
||||||
|
return encodeErr
|
||||||
|
}
|
||||||
|
fmt.Println(string(encoded))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func runBootstrap(args []string) error {
|
func runBootstrap(args []string) error {
|
||||||
flags := flag.NewFlagSet("bootstrap", flag.ContinueOnError)
|
flags := flag.NewFlagSet("bootstrap", flag.ContinueOnError)
|
||||||
var in mysql.BootstrapInput
|
var in mysql.BootstrapInput
|
||||||
|
|||||||
@@ -159,4 +159,6 @@ Orbit 数据库事务不能自动包含 接入方的业务事务。SDK 的事务
|
|||||||
- 恢复旧备份后,可能已有外部业务效果而平台记录回退。必须停止派发、使恢复前的会话与租约失效,并完成必要对账后再开放执行。
|
- 恢复旧备份后,可能已有外部业务效果而平台记录回退。必须停止派发、使恢复前的会话与租约失效,并完成必要对账后再开放执行。
|
||||||
- 数据库故障切换与备份恢复是不同故障模型,分别定义验证和可接受损失范围。
|
- 数据库故障切换与备份恢复是不同故障模型,分别定义验证和可接受损失范围。
|
||||||
|
|
||||||
|
当前可用的[`orbit-admin retention inventory`](api/retention.md)只提供按 UTC 截止时间的数量盘点,不执行归档或删除;保留周期、归档格式和受保护记录核对完成前,不得把盘点结果当作清理授权。
|
||||||
|
|
||||||
MySQL 持久化建议基线为 `innodb_flush_log_at_trx_commit=1`,启用 binlog 时采用 `sync_binlog=1`。副本故障切换的确认语义、RPO / RTO 仍要由具体高可用方案决定。[MySQL 持久化配置](https://dev.mysql.com/doc/refman/8.4/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit)
|
MySQL 持久化建议基线为 `innodb_flush_log_at_trx_commit=1`,启用 binlog 时采用 `sync_binlog=1`。副本故障切换的确认语义、RPO / RTO 仍要由具体高可用方案决定。[MySQL 持久化配置](https://dev.mysql.com/doc/refman/8.4/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit)
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ P4/P5定时等待与后续查询轮次的实现及回归记录见[时钟报告](
|
|||||||
1. 已补[首批可复现故障工具](reports/phase-6-fault-boundaries.md):A04“派发已提交但消息尚未送达”、W01/W13事务提交结果不明,以及W16最终回执/旧PENDING结果重放/下一轮竞争。每个切点必须有实际数据库或进程证据,不能用响应错误推断事务是否已提交,也不能用普通SIGNAL竞争替代最终查询场景。
|
1. 已补[首批可复现故障工具](reports/phase-6-fault-boundaries.md):A04“派发已提交但消息尚未送达”、W01/W13事务提交结果不明,以及W16最终回执/旧PENDING结果重放/下一轮竞争。每个切点必须有实际数据库或进程证据,不能用响应错误推断事务是否已提交,也不能用普通SIGNAL竞争替代最终查询场景。
|
||||||
2. 已实现[基础运行观测](api/observability.md)及[有界业务状态与事件采样](reports/phase-6-business-observability.md):HTTP/WS、数据库连接池、后台批次、固定状态计数、最近事件类别、终态耗时样本、最早年龄、截断/新鲜度指标和可离线验证的告警规则;独立采集监听默认关闭,固定指标目录拒绝动态标签;发布前只读结构核验由[`orbit-admin verify`](api/operations.md)提供。仍需受理/授权阶段端到端延迟与全局持久吞吐、流程Inbox推进延迟、全局发送队列、多节点聚合及生产采集/通知验证。
|
2. 已实现[基础运行观测](api/observability.md)及[有界业务状态与事件采样](reports/phase-6-business-observability.md):HTTP/WS、数据库连接池、后台批次、固定状态计数、最近事件类别、终态耗时样本、最早年龄、截断/新鲜度指标和可离线验证的告警规则;独立采集监听默认关闭,固定指标目录拒绝动态标签;发布前只读结构核验由[`orbit-admin verify`](api/operations.md)提供。仍需受理/授权阶段端到端延迟与全局持久吞吐、流程Inbox推进延迟、全局发送队列、多节点聚合及生产采集/通知验证。
|
||||||
3. 已补齐受保护管理环境中的固定凭据操作文件、轮换、撤销、幂等回执和脱敏管理审计;轮换保留授权绑定并要求新令牌重新建立会话,撤销允许在停用范围内执行且不改写历史记录。仍需补齐提交不明故障切点、多节点安全重绑演练、凭据最小权限配置核对和生产密钥托管/审计演练。
|
3. 已补齐受保护管理环境中的固定凭据操作文件、轮换、撤销、幂等回执和脱敏管理审计;轮换保留授权绑定并要求新令牌重新建立会话,撤销允许在停用范围内执行且不改写历史记录。仍需补齐提交不明故障切点、多节点安全重绑演练、凭据最小权限配置核对和生产密钥托管/审计演练。
|
||||||
4. 实现保留/归档与受保护记录核对,再执行备份恢复、兼容升级和六类容量负载。未确认交付、有效幂等身份、当前/历史执行证据和未终结流程不能被普通清理破坏。生产HA及RPO/RTO继续按实际拓扑验证,不缩减为本机多进程检查。
|
4. 已补[`orbit-admin retention inventory`](api/retention.md)只读盘点和[阶段报告](reports/phase-6-retention-inventory.md),能区分过期幂等、确定终态、未知效果、未终结流程、已确认/未确认交付、已消费/未消费Inbox、事件和审计规模;它不执行归档或删除。后续仍需评审各类保留周期、归档格式、受保护记录核对,再执行备份恢复、兼容升级和六类容量负载。未确认交付、有效幂等身份、当前/历史执行证据和未终结流程不能被普通清理破坏。生产HA及RPO/RTO继续按实际拓扑验证,不缩减为本机多进程检查。
|
||||||
|
|
||||||
### P3 功能范围核对
|
### P3 功能范围核对
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
| 任务 `priority` 与节点领取池 | P3 已实现有界优先级加速、应用/队列轮转 | [优先级与公平派发](priority-and-fairness.md) |
|
| 任务 `priority` 与节点领取池 | P3 已实现有界优先级加速、应用/队列轮转 | [优先级与公平派发](priority-and-fairness.md) |
|
||||||
| 凭据校验、初始化、固定操作文件轮换/撤销与回执重放 CLI | P1/P6 已实现;不提供公网管理路由,测试专用提交不明切点已回归 | [鉴权](authentication.md)、[凭据报告](../reports/phase-6-credentials.md) |
|
| 凭据校验、初始化、固定操作文件轮换/撤销与回执重放 CLI | P1/P6 已实现;不提供公网管理路由,测试专用提交不明切点已回归 | [鉴权](authentication.md)、[凭据报告](../reports/phase-6-credentials.md) |
|
||||||
| `orbit-admin verify` 发布前结构核验 | 已实现只读迁移、零外键和 000026–000028 固定索引检查 | [运维核验](operations.md) |
|
| `orbit-admin verify` 发布前结构核验 | 已实现只读迁移、零外键和 000026–000028 固定索引检查 | [运维核验](operations.md) |
|
||||||
|
| `orbit-admin retention inventory` 保留清单 | 已实现带 UTC 截止时间的只读盘点;不执行归档、删除或权限变更 | [保留清单](retention.md) |
|
||||||
| `/v1/worker/connect` | P2 已实现并通过阶段验收 | [Worker 契约](worker.md)、[Schema](worker-schema.md) |
|
| `/v1/worker/connect` | P2 已实现并通过阶段验收 | [Worker 契约](worker.md)、[Schema](worker-schema.md) |
|
||||||
| 任务相对延迟 `delay_ms` | 已实现数据库计时、原键恢复与实际执行例子 | [任务接口](tasks.md)、[延迟示例](../examples/delayed-task.md) |
|
| 任务相对延迟 `delay_ms` | 已实现数据库计时、原键恢复与实际执行例子 | [任务接口](tasks.md)、[延迟示例](../examples/delayed-task.md) |
|
||||||
| 任务冻结策略与 Worker `retryable` | P3 安全重试已实现 | [安全重试](retries.md) |
|
| 任务冻结策略与 Worker `retryable` | P3 安全重试已实现 | [安全重试](retries.md) |
|
||||||
|
|||||||
19
docs/api/retention.md
Normal file
19
docs/api/retention.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# 保留清单(只读)
|
||||||
|
|
||||||
|
`orbit-admin retention inventory` 用于在制定保留窗口、归档和备份恢复方案前盘点历史数据。它只执行带截止时间的统计查询,不删除、搬迁、改写数据,也不会自动判断某条记录可以安全归档。
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ORBIT_MYSQL_DSN='user:password@tcp(127.0.0.1:3306)/orbit' \
|
||||||
|
go run ./cmd/orbit-admin retention inventory \
|
||||||
|
--before 2026-09-18T00:00:00Z
|
||||||
|
```
|
||||||
|
|
||||||
|
示例输出:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"cutoff":"2026-09-18T00:00:00Z","expired_idempotency":0,"terminal_tasks":0,"uncertain_tasks":0,"active_tasks":0,"terminal_workflows":0,"active_workflows":0,"acknowledged_deliveries":0,"unconfirmed_deliveries":0,"processed_inbox":0,"unprocessed_inbox":0,"events":0,"audit_events":0}
|
||||||
|
```
|
||||||
|
|
||||||
|
所有时间按 UTC 解析,严格早于 `--before` 的记录才计入。截止时间不能晚于数据库当前时间,避免把未来记录误认为历史。`terminal_tasks` 只统计确定终态且 `effect_uncertain=false` 的任务;`uncertain_tasks`、`active_tasks`、`active_workflows`、`unconfirmed_deliveries` 和 `unprocessed_inbox` 是需要先处理或保留的阻塞项。
|
||||||
|
|
||||||
|
结果是盘点快照,不是归档授权。真正的清理或归档还必须完成保留周期评审、未确认副作用核对、事件投递和流程推进核对、备份恢复演练、权限隔离及审计;当前命令没有 `apply` 或删除路径。
|
||||||
25
docs/reports/phase-6-retention-inventory.md
Normal file
25
docs/reports/phase-6-retention-inventory.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# P6:保留清单与归档前置核对
|
||||||
|
|
||||||
|
日期:2026-09-19。本批先交付只读盘点,避免在保留周期、备份恢复和外部效果尚未评审时提供危险的自动删除入口。
|
||||||
|
|
||||||
|
## 已实现
|
||||||
|
|
||||||
|
- [`ReadRetentionInventory`](../../internal/storage/mysql/retention_inventory.go) 接受明确的 UTC 截止时间,只统计严格早于截止时间的记录。
|
||||||
|
- `orbit-admin retention inventory --before RFC3339` 通过独立管理命令输出 JSON;数据库时间校验会拒绝未来截止时间,数据库连接、查询失败不会泄露 DSN 或 SQL。
|
||||||
|
- 盘点固定覆盖幂等、确定终态/未知效果/未终结任务、确定终态/未终结流程、已确认/未确认交付、已消费/未消费流程 Inbox、追加事件和管理审计。
|
||||||
|
- 任何查询只读,不执行 DDL、删除、搬迁、权限修改或幂等重置;CLI 没有 `apply` 参数。未确认交付、未消费 Inbox、未知效果和未终结实体被单独列为阻塞数量。
|
||||||
|
|
||||||
|
## 回归证据
|
||||||
|
|
||||||
|
- `go test ./cmd/orbit-admin ./internal/storage/mysql` 通过;存储集成用例使用真实 MySQL 验证:明确放到截止时间之前的确定终态任务计入 `terminal_tasks`,未知效果为零,未来截止被拒绝。
|
||||||
|
- 标准 `DOCKER=... GO=... sh scripts/test-mysql.sh` 在 Go 1.27.1、Docker MySQL 8.4.10 环境退出码为 0。脚本实际输出:
|
||||||
|
|
||||||
|
```text
|
||||||
|
{"cutoff":"2000-01-01T00:00:00Z","expired_idempotency":0,"terminal_tasks":0,"uncertain_tasks":0,"active_tasks":0,"terminal_workflows":0,"active_workflows":0,"acknowledged_deliveries":0,"unconfirmed_deliveries":0,"processed_inbox":0,"unprocessed_inbox":0,"events":0,"audit_events":0}
|
||||||
|
```
|
||||||
|
|
||||||
|
同轮已有迁移、零外键、凭据、Pulse/Weave 真实进程强杀恢复、SDK 和两个独立业务示例均通过。
|
||||||
|
|
||||||
|
## 边界与后续
|
||||||
|
|
||||||
|
盘点数量不是归档授权,也不证明某类记录可独立删除。正式归档前仍需确定每类保留周期和归档格式,核对事件交付、流程推进、有效幂等身份、未知外部效果、审计保留与备份恢复;还需要隔离环境恢复演练、权限隔离、容量和生产拓扑验证。当前没有自动清理路径,防止把测试环境的历史数量误当成生产策略。
|
||||||
@@ -98,4 +98,15 @@ func TestIntegrationOperationalSnapshot(t *testing.T) {
|
|||||||
if _, err := ReadOperationalSnapshot(cancelled, db); err == nil {
|
if _, err := ReadOperationalSnapshot(cancelled, db); err == nil {
|
||||||
t.Fatal("cancelled context unexpectedly completed snapshot")
|
t.Fatal("cancelled context unexpectedly completed snapshot")
|
||||||
}
|
}
|
||||||
|
f.exec("UPDATE pulse_tasks SET completed_at=DATE_SUB(UTC_TIMESTAMP(6), INTERVAL 2 HOUR), updated_at=UTC_TIMESTAMP(6) WHERE namespace_id=? AND id=?", f.resources.NamespaceID, task.ID)
|
||||||
|
inventory, err := ReadRetentionInventory(ctx, db, time.Now().UTC().Add(-time.Hour))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if inventory.Cutoff.IsZero() || inventory.TerminalTasks == 0 || inventory.UncertainTasks != 0 {
|
||||||
|
t.Fatalf("retention inventory=%+v", inventory)
|
||||||
|
}
|
||||||
|
if _, err := ReadRetentionInventory(ctx, db, time.Now().UTC().Add(time.Hour)); err == nil {
|
||||||
|
t.Fatal("future retention cutoff unexpectedly accepted")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
83
internal/storage/mysql/retention_inventory.go
Normal file
83
internal/storage/mysql/retention_inventory.go
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package mysql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RetentionInventory 是指定截止时间前的只读保留清单。
|
||||||
|
// 它只提供核对数量,不代表记录已经满足归档条件,也不执行删除或搬迁。
|
||||||
|
type RetentionInventory struct {
|
||||||
|
// Cutoff 是清单使用的 UTC 截止时间,严格早于该时间的记录才会计入。
|
||||||
|
Cutoff time.Time `json:"cutoff"`
|
||||||
|
// ExpiredIdempotency 是已过幂等保留期的请求记录数量。
|
||||||
|
ExpiredIdempotency uint64 `json:"expired_idempotency"`
|
||||||
|
// TerminalTasks 是已进入确定终态且已完成的任务数量。
|
||||||
|
TerminalTasks uint64 `json:"terminal_tasks"`
|
||||||
|
// UncertainTasks 是仍带未知效果的任务数量,必须人工核对后才能处理。
|
||||||
|
UncertainTasks uint64 `json:"uncertain_tasks"`
|
||||||
|
// ActiveTasks 是尚未终结的任务数量,不能进入普通历史归档。
|
||||||
|
ActiveTasks uint64 `json:"active_tasks"`
|
||||||
|
// TerminalWorkflows 是已进入确定终态且已完成的流程数量。
|
||||||
|
TerminalWorkflows uint64 `json:"terminal_workflows"`
|
||||||
|
// ActiveWorkflows 是尚未终结的流程数量,不能进入普通历史归档。
|
||||||
|
ActiveWorkflows uint64 `json:"active_workflows"`
|
||||||
|
// AcknowledgedDeliveries 是已经确认的结果交付数量。
|
||||||
|
AcknowledgedDeliveries uint64 `json:"acknowledged_deliveries"`
|
||||||
|
// UnconfirmedDeliveries 是仍未确认的结果交付数量,不能无声清理。
|
||||||
|
UnconfirmedDeliveries uint64 `json:"unconfirmed_deliveries"`
|
||||||
|
// ProcessedInbox 是已经完成内部消费的流程事件数量。
|
||||||
|
ProcessedInbox uint64 `json:"processed_inbox"`
|
||||||
|
// UnprocessedInbox 是尚未完成内部消费的流程事件数量,不能清理。
|
||||||
|
UnprocessedInbox uint64 `json:"unprocessed_inbox"`
|
||||||
|
// Events 是截止时间前追加的不可变事件数量。
|
||||||
|
Events uint64 `json:"events"`
|
||||||
|
// AuditEvents 是截止时间前追加的管理审计数量,默认应单独保留。
|
||||||
|
AuditEvents uint64 `json:"audit_events"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadRetentionInventory performs bounded-by-time, read-only count queries.
|
||||||
|
// It deliberately does not decide policy or mutate any table; callers must
|
||||||
|
// review retention windows, backups, outstanding effects and audit rules first.
|
||||||
|
func ReadRetentionInventory(ctx context.Context, db *sql.DB, cutoff time.Time) (RetentionInventory, error) {
|
||||||
|
if db == nil {
|
||||||
|
return RetentionInventory{}, errors.New("database is required")
|
||||||
|
}
|
||||||
|
if cutoff.IsZero() {
|
||||||
|
return RetentionInventory{}, errors.New("cutoff is required")
|
||||||
|
}
|
||||||
|
cutoff = cutoff.UTC()
|
||||||
|
var now time.Time
|
||||||
|
if err := db.QueryRowContext(ctx, "SELECT UTC_TIMESTAMP(6)").Scan(&now); err != nil {
|
||||||
|
return RetentionInventory{}, errors.New("database time unavailable")
|
||||||
|
}
|
||||||
|
if cutoff.After(now.UTC()) {
|
||||||
|
return RetentionInventory{}, errors.New("cutoff cannot be in the future")
|
||||||
|
}
|
||||||
|
result := RetentionInventory{Cutoff: cutoff}
|
||||||
|
queries := []struct {
|
||||||
|
destination *uint64
|
||||||
|
query string
|
||||||
|
}{
|
||||||
|
{&result.ExpiredIdempotency, "SELECT COUNT(*) FROM orbit_idempotency_keys WHERE expires_at<?"},
|
||||||
|
{&result.TerminalTasks, "SELECT COUNT(*) FROM pulse_tasks WHERE state IN ('SUCCEEDED','FAILED','CANCELLED') AND completed_at IS NOT NULL AND completed_at<? AND effect_uncertain=FALSE"},
|
||||||
|
{&result.UncertainTasks, "SELECT COUNT(*) FROM pulse_tasks WHERE effect_uncertain=TRUE AND created_at<?"},
|
||||||
|
{&result.ActiveTasks, "SELECT COUNT(*) FROM pulse_tasks WHERE state NOT IN ('SUCCEEDED','FAILED','CANCELLED') AND created_at<?"},
|
||||||
|
{&result.TerminalWorkflows, "SELECT COUNT(*) FROM weave_instances WHERE state IN ('SUCCEEDED','FAILED','CANCELLED') AND completed_at IS NOT NULL AND completed_at<?"},
|
||||||
|
{&result.ActiveWorkflows, "SELECT COUNT(*) FROM weave_instances WHERE state NOT IN ('SUCCEEDED','FAILED','CANCELLED') AND created_at<?"},
|
||||||
|
{&result.AcknowledgedDeliveries, "SELECT COUNT(*) FROM orbit_deliveries WHERE state='ACKED' AND acknowledged_at IS NOT NULL AND acknowledged_at<?"},
|
||||||
|
{&result.UnconfirmedDeliveries, "SELECT COUNT(*) FROM orbit_deliveries WHERE state<>'ACKED' AND created_at<?"},
|
||||||
|
{&result.ProcessedInbox, "SELECT COUNT(*) FROM weave_inbox WHERE state='PROCESSED' AND processed_at IS NOT NULL AND processed_at<?"},
|
||||||
|
{&result.UnprocessedInbox, "SELECT COUNT(*) FROM weave_inbox WHERE state<>'PROCESSED' AND created_at<?"},
|
||||||
|
{&result.Events, "SELECT COUNT(*) FROM orbit_events WHERE occurred_at<?"},
|
||||||
|
{&result.AuditEvents, "SELECT COUNT(*) FROM orbit_audit_events WHERE created_at<?"},
|
||||||
|
}
|
||||||
|
for _, item := range queries {
|
||||||
|
if err := db.QueryRowContext(ctx, item.query, cutoff).Scan(item.destination); err != nil {
|
||||||
|
return RetentionInventory{}, errors.New("retention inventory unavailable")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
@@ -45,6 +45,7 @@ ORBIT_TEST_SERVER_BINARY="$TASK_TEST_DIR/orbit" "$TASK_GO" test -race -count=1 -
|
|||||||
"$TASK_GO" build -o "$TASK_TEST_DIR/orbit-admin" ./cmd/orbit-admin
|
"$TASK_GO" build -o "$TASK_TEST_DIR/orbit-admin" ./cmd/orbit-admin
|
||||||
ORBIT_MYSQL_DSN="$ORBIT_TEST_MYSQL_DSN" "$TASK_TEST_DIR/orbit-migrate" status
|
ORBIT_MYSQL_DSN="$ORBIT_TEST_MYSQL_DSN" "$TASK_TEST_DIR/orbit-migrate" status
|
||||||
ORBIT_MYSQL_DSN="$ORBIT_TEST_MYSQL_DSN" "$TASK_TEST_DIR/orbit-admin" verify
|
ORBIT_MYSQL_DSN="$ORBIT_TEST_MYSQL_DSN" "$TASK_TEST_DIR/orbit-admin" verify
|
||||||
|
ORBIT_MYSQL_DSN="$ORBIT_TEST_MYSQL_DSN" "$TASK_TEST_DIR/orbit-admin" retention inventory --before 2000-01-01T00:00:00Z
|
||||||
ORBIT_MYSQL_DSN="$ORBIT_TEST_MYSQL_DSN" "$TASK_TEST_DIR/orbit-admin" bootstrap --application sdk-example --namespace default --environment test --queue files --output "$TASK_TEST_DIR/sdk.credentials.json"
|
ORBIT_MYSQL_DSN="$ORBIT_TEST_MYSQL_DSN" "$TASK_TEST_DIR/orbit-admin" bootstrap --application sdk-example --namespace default --environment test --queue files --output "$TASK_TEST_DIR/sdk.credentials.json"
|
||||||
ORBIT_MYSQL_DSN="$ORBIT_TEST_MYSQL_DSN" ORBIT_HTTP_ADDR=127.0.0.1:0 "$TASK_TEST_DIR/orbit" > "$TASK_TEST_DIR/server.log" 2>&1 &
|
ORBIT_MYSQL_DSN="$ORBIT_TEST_MYSQL_DSN" ORBIT_HTTP_ADDR=127.0.0.1:0 "$TASK_TEST_DIR/orbit" > "$TASK_TEST_DIR/server.log" 2>&1 &
|
||||||
TASK_SERVER_PID=$!
|
TASK_SERVER_PID=$!
|
||||||
|
|||||||
Reference in New Issue
Block a user