Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/en/operations/health-metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ Failed check:

## Background Task Activity

The dashboard overview counts this node's data sets and their providers. The Providers page shows the full observed provider list.

SynapS3 reports an unhealthy task processor when it stops reporting activity for longer than its configured health window. This detects stalled background storage even when no upload is active.

Check background task state:
Expand Down
4 changes: 2 additions & 2 deletions docs/en/operations/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,11 @@ Retry only after RPC connectivity, storage provider availability, wallet funds,
synaps3 admin task retry 42
```

The API indicates whether Retry is available for each failed task. Provider replacement work is recovered from **Details** → **Storage** → **Data Sets**. A wallet operation can be recovered from Tasks only when no broadcast started; an uncertain broadcast remains non-retryable. An uncertain Store offers **Check again**, which observes the provider without uploading again. For remote-copy removal that remains unconfirmed after 24 hours, **Recover** checks the chain first and may submit another paid request if the copy is still present and not queued; the earlier request may still succeed. If the data set is no longer active, the chain cannot confirm this individual removal, so the task keeps checking instead of claiming the copy is gone. Use **Dismiss** or `synaps3 admin task acknowledge <id>` only after reviewing the failure; acknowledged tasks remain available for the configured retention period before cleanup. When failures have piled up, **Dismiss all** on the Tasks page clears the ones the current Operation filter selects, and `synaps3 admin task acknowledge --type <operation> --yes` does the same from the CLI; failures recorded after you confirm stay in the list.
The API indicates whether Retry is available for each failed task. Provider replacement work is recovered from **Details** → **Storage** → **Data Sets**. A wallet operation can be recovered from Tasks only when no broadcast started; an uncertain broadcast remains non-retryable. A failed Store offers **Retry upload**; it checks the provider first and resends the piece only if missing. For remote-copy removal that remains unconfirmed after 24 hours, **Recover** checks the chain first and may submit another paid request if the copy is still present and not queued; the earlier request may still succeed. If the data set is no longer active, the chain cannot confirm this individual removal, so the task keeps checking instead of claiming the copy is gone. Use **Dismiss** or `synaps3 admin task acknowledge <id>` only after reviewing the failure; acknowledged tasks remain available for the configured retention period before cleanup. When failures have piled up, **Dismiss all** on the Tasks page clears the ones the current Operation filter selects, and `synaps3 admin task acknowledge --type <operation> --yes` does the same from the CLI; failures recorded after you confirm stay in the list.

## Provider or RPC Issues

Check provider health and Filecoin readiness in the dashboard, or inspect the Admin API:
Check this node's storage health on Overview and Filecoin readiness in Settings, or inspect the Admin API:

```bash
curl -u admin http://127.0.0.1:9090/api/v1/filecoin/readiness
Expand Down
2 changes: 1 addition & 1 deletion docs/en/operations/upgrade-recovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ After a restart, unfinished work becomes eligible to continue automatically.
- Retry a failed task only when the dashboard or API marks it retryable.
- Recover provider replacements from **Details** → **Storage** → **Data Sets**.
- A wallet operation can be retried from Tasks only when no broadcast started. An uncertain broadcast remains non-retryable.
- For an uncertain Store, **Check again** checks the provider without uploading the object again.
- **Retry upload** checks whether the provider has the piece, then uploads it again if missing. A repeat can use more bandwidth or open another upload session.
- `status=failed` lists unacknowledged failures. Use `status=dismissed` to list acknowledged failures.
- Review unresolved storage confirmations with `synaps3 admin storage-confirmation list`.

Expand Down
2 changes: 1 addition & 1 deletion docs/en/reference/cli-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Admin global flags must appear after `admin` and before the subcommand:

Task listing supports `--type`, `--status`, `--limit`, and ID-based `--cursor`. Valid status filters are `pending`, `running`, `completed`, `failed`, `cancelled`, and `dismissed`. Pending work is presented as queued, scheduled, or waiting; `failed` returns unacknowledged failures and `dismissed` returns acknowledged failures.

`synaps3 admin task retry` recovers only tasks whose response says they are retryable. Provider replacement recovery remains under **Details** → **Storage** → **Data Sets**. A wallet operation can be retried only when its broadcast never started; an operation with an uncertain broadcast remains non-retryable. For an uncertain Store, the dashboard labels Retry as **Check again**: this checks the provider without uploading again. For remote-copy removal that remains unconfirmed after 24 hours, Recover checks whether the copy is gone or already queued for removal; otherwise it may submit another paid request, even though the earlier request may still succeed. Use `synaps3 admin task acknowledge <id>` to dismiss a failed task after reviewing its outcome; acknowledgement starts its retention period, after which it may be cleaned up. To clear a backlog, run it without an ID and confirm with `--yes`: `--type` limits it to one operation, and `--before` sets an RFC 3339 cutoff that defaults to now, so failures recorded later stay visible.
`synaps3 admin task retry` recovers only tasks whose response says they are retryable. Provider replacement recovery remains under **Details** → **Storage** → **Data Sets**. A wallet operation can be retried only when its broadcast never started; an operation with an uncertain broadcast remains non-retryable. For a failed Store, **Retry upload** checks the provider first and sends the piece again only if missing. For remote-copy removal that remains unconfirmed after 24 hours, Recover checks whether the copy is gone or already queued for removal; otherwise it may submit another paid request, even though the earlier request may still succeed. Use `synaps3 admin task acknowledge <id>` to dismiss a failed task after reviewing its outcome; acknowledgement starts its retention period, after which it may be cleaned up. To clear a backlog, run it without an ID and confirm with `--yes`: `--type` limits it to one operation, and `--before` sets an RFC 3339 cutoff that defaults to now, so failures recorded later stay visible.

`synaps3 admin storage-confirmation list` shows storage confirmations that need review. Verify the piece CID, provider, current attempt ID, attempted time, and any available transaction evidence before running `storage-confirmation release <copy-id> --attempt-id <attempt-id> --yes`; release only if you accept that the provider may already store the piece and resubmission may create duplicate paid storage. A stale attempt ID is refused.

Expand Down
2 changes: 2 additions & 0 deletions docs/zh/operations/health-metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ curl http://127.0.0.1:9090/healthz

## 后台任务活动

仪表盘概览只统计本节点的数据集及其存储提供方;Providers 页面仍显示完整的观测名单。

如果后台任务处理长时间没有在配置的健康窗口内报告活动,SynapS3 会将其标记为不健康。即使没有正在上传的对象,这项检查也能发现后台存储已经停滞。

检查后台任务状态:
Expand Down
4 changes: 2 additions & 2 deletions docs/zh/operations/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,11 @@ synaps3 admin task list --status failed --limit 100
synaps3 admin task retry 42
```

API 会标明每个失败任务是否可使用 Retry。存储提供方替换从 **Details** → **Storage** → **Data Sets** 恢复。只有尚未发出广播的钱包操作可以从 Tasks 恢复;广播结果不确定时仍不可重试。Store 结果不确定时会提供 **Check again**,它只观察存储提供方,不会再次上传。远端副本删除超过 24 小时仍无法确认时,**Recover** 会先检查链上状态;若副本仍存在且未排队删除,可能再次提交付费请求,而先前的请求仍可能成功。若数据集在链上不再活跃,链上无法据此确认这份副本已删除,任务会继续核查,不会将其记为已删除。只有在核对失败结果后才使用 **Dismiss** 或 `synaps3 admin task acknowledge <id>`;确认后的任务会继续保留配置的时长,再由后台清理。失败任务积压时,任务页的 **Dismiss all** 会处理当前操作类型筛选下的失败任务,命令行对应 `synaps3 admin task acknowledge --type <操作> --yes`;在你确认之后才记录的失败仍会留在列表里。
API 会标明每个失败任务是否可使用 Retry。存储提供方替换从 **Details** → **Storage** → **Data Sets** 恢复。只有尚未发出广播的钱包操作可以从 Tasks 恢复;广播结果不确定时仍不可重试。Store 失败时可使用 **Retry upload**;它先检查提供方,确认分片缺失才重新上传。远端副本删除超过 24 小时仍无法确认时,**Recover** 会先检查链上状态;若副本仍存在且未排队删除,可能再次提交付费请求,而先前的请求仍可能成功。若数据集在链上不再活跃,链上无法据此确认这份副本已删除,任务会继续核查,不会将其记为已删除。只有在核对失败结果后才使用 **Dismiss** 或 `synaps3 admin task acknowledge <id>`;确认后的任务会继续保留配置的时长,再由后台清理。失败任务积压时,任务页的 **Dismiss all** 会处理当前操作类型筛选下的失败任务,命令行对应 `synaps3 admin task acknowledge --type <操作> --yes`;在你确认之后才记录的失败仍会留在列表里。

## 存储提供方或 RPC 问题

在仪表盘查看存储提供方健康状态和 Filecoin readiness,或检查 Admin API:
在 Overview 查看本节点存储健康状态,在 Settings 查看 Filecoin readiness,或检查 Admin API:

```bash
curl -u admin http://127.0.0.1:9090/api/v1/filecoin/readiness
Expand Down
2 changes: 1 addition & 1 deletion docs/zh/operations/upgrade-recovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ SynapS3 不会修改不兼容的数据库。废弃的 `worker.upload`、`worker.
- 只重试仪表盘或 API 标记为可重试的失败任务。
- 从 **Details** → **Storage** → **Data Sets** 恢复存储提供方替换。
- 钱包操作只有在尚未发出广播时才能从 Tasks 重试;广播结果不确定时仍不可重试。
- Store 结果不确定时,**Check again** 只查询存储提供方,不会重新上传对象。
- **Retry upload** 会先检查存储提供方是否已有分片;确认缺失后才重新上传。重传可能增加带宽用量或开启另一次上传会话。
- `status=failed` 只列出尚未确认的失败;使用 `status=dismissed` 查看已确认的失败。
- 使用 `synaps3 admin storage-confirmation list` 核对尚未解决的存储确认。

Expand Down
2 changes: 1 addition & 1 deletion docs/zh/reference/cli-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Admin 全局 flags 必须放在 `admin` 之后、子命令之前:

列出后台任务时支持 `--type`、`--status`、`--limit` 和基于任务 ID 的 `--cursor`。有效的状态过滤值为 `pending`、`running`、`completed`、`failed`、`cancelled` 和 `dismissed`。pending 工作会显示为 queued、scheduled 或 waiting;`failed` 返回尚未确认的失败,`dismissed` 返回已确认的失败。

`synaps3 admin task retry` 只恢复响应中标记为可重试的失败任务。存储提供方替换仍在 **Details** → **Storage** → **Data Sets** 中恢复。只有尚未发出广播的钱包操作可以重试;广播结果不确定时仍不可重试。Store 结果不确定时,dashboard 会把 Retry 显示为 **Check again**:该操作只查询存储提供方,不会重新上传。远端副本删除超过 24 小时仍无法确认时,**Recover** 会先检查副本是否已删除或已排队删除;若仍存在且未排队,可能再次提交付费删除请求,而先前的请求仍可能成功。核对失败结果后,可用 `synaps3 admin task acknowledge <id>` 将任务标记为已处理;确认后开始计算保留期,到期后可能被清理。需要清理积压时,不带 ID 运行并用 `--yes` 确认:`--type` 限定某一种操作,`--before` 指定 RFC 3339 截止时刻(默认为当前时间),该时刻之后记录的失败仍然可见。
`synaps3 admin task retry` 只恢复响应中标记为可重试的失败任务。存储提供方替换仍在 **Details** → **Storage** → **Data Sets** 中恢复。只有尚未发出广播的钱包操作可以重试;广播结果不确定时仍不可重试。Store 失败后,**Retry upload** 会先检查提供方;确认分片缺失才再次上传。远端副本删除超过 24 小时仍无法确认时,**Recover** 会先检查副本是否已删除或已排队删除;若仍存在且未排队,可能再次提交付费删除请求,而先前的请求仍可能成功。核对失败结果后,可用 `synaps3 admin task acknowledge <id>` 将任务标记为已处理;确认后开始计算保留期,到期后可能被清理。需要清理积压时,不带 ID 运行并用 `--yes` 确认:`--type` 限定某一种操作,`--before` 指定 RFC 3339 截止时刻(默认为当前时间),该时刻之后记录的失败仍然可见。

`synaps3 admin storage-confirmation list` 会显示需要核对的存储确认。核对存储提供方、transaction 和当前 attempt 后,使用 `storage-confirmation release <copy-id> --attempt-id <attempt-id> --yes` 表示确认存储提供方可能已经接受该 piece,并允许正常恢复流程再次提交。过期的 attempt ID 会被拒绝。

Expand Down
80 changes: 59 additions & 21 deletions internal/admin/api_overview.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,38 +184,76 @@ func (s *Server) filecoinStorageHealthOverview(ctx context.Context) filecoinStor
return health
}

providers, err := s.observability.ListProviderObservations(ctx, observability.ListOptions{Limit: 1})
dataSetRows, providerStates, dataSetStates, providerCheckedAt, dataSetCheckedAt, err := s.repos.Observability.OverviewStorageStates(ctx)
if err != nil {
if s.logger != nil {
s.logger.Warn("overview: failed to load provider observability summary", "error", err)
s.logger.Warn("overview: failed to load storage observability summary", "error", err)
}
health.PartialErrors["observability_providers"] = "provider health query failed"
health.PartialErrors["observability"] = "storage health query failed"
health.Level = observability.WorstSignalLevel(health.Level, observability.SignalWarning)
} else {
health.Providers = &filecoinStorageHealthObservationOverview{
Summary: providers.Summary,
SummarySignal: providers.SummarySignal,
}
health.Level = observability.WorstSignalLevel(health.Level, providers.SummarySignal.Level)
return health
}

dataSets, err := s.observability.ListDataSetObservations(ctx, observability.ListOptions{Limit: 1})
if err != nil {
if s.logger != nil {
s.logger.Warn("overview: failed to load data set observability summary", "error", err)
providerByID := make(map[string]observability.ProviderState, len(providerStates))
for _, state := range providerStates {
providerByID[state.ProviderID.String()] = state
providerCheckedAt = olderOverviewObservation(providerCheckedAt, state.LastCheckedAt)
}
dataSetByID := make(map[int64]observability.DataSetState, len(dataSetStates))
for _, state := range dataSetStates {
dataSetByID[state.LocalDataSetID] = state
dataSetCheckedAt = olderOverviewObservation(dataSetCheckedAt, state.LastCheckedAt)
}
providers := observability.Summary{}
dataSets := observability.Summary{Total: len(dataSetRows)}
seenProviders := make(map[string]bool, len(dataSetRows))
for _, row := range dataSetRows {
if state, ok := dataSetByID[row.ID]; ok {
addStorageHealthStatus(&dataSets, state.Status)
} else {
dataSets.Unknown++
}
health.PartialErrors["observability_data_sets"] = "data set health query failed"
health.Level = observability.WorstSignalLevel(health.Level, observability.SignalWarning)
} else {
health.DataSets = &filecoinStorageHealthObservationOverview{
Summary: dataSets.Summary,
SummarySignal: dataSets.SummarySignal,
id := row.ProviderID.String()
if seenProviders[id] {
continue
}
seenProviders[id] = true
providers.Total++
if state, ok := providerByID[id]; ok {
addStorageHealthStatus(&providers, state.Status)
} else {
providers.Unknown++
}
health.Level = observability.WorstSignalLevel(health.Level, dataSets.SummarySignal.Level)
}
now := time.Now().UTC()
interval := s.observability.RefreshInterval()
providerSignal := observability.DefaultAttentionSummarySignal(providers, providerCheckedAt, interval, now)
dataSetSignal := observability.DefaultAttentionSummarySignal(dataSets, dataSetCheckedAt, interval, now)
health.Providers = &filecoinStorageHealthObservationOverview{Summary: providers, SummarySignal: providerSignal}
health.DataSets = &filecoinStorageHealthObservationOverview{Summary: dataSets, SummarySignal: dataSetSignal}
health.Level = observability.WorstSignalLevel(providerSignal.Level, dataSetSignal.Level)
return health
}

func olderOverviewObservation(current *time.Time, observed time.Time) *time.Time {
if observed.IsZero() || (current != nil && !observed.Before(*current)) {
return current
}
return &observed
}

func addStorageHealthStatus(summary *observability.Summary, status observability.Status) {
switch status {
case observability.StatusAvailable:
summary.Available++
case observability.StatusDegraded:
summary.Degraded++
case observability.StatusUnavailable:
summary.Unavailable++
default:
summary.Unknown++
}
}

func taskPipelineOverviewRows(counts []repository.TaskPipelineCount) []taskPipelineOverview {
rows := make([]taskPipelineOverview, 0)
index := make(map[string]int)
Expand Down
Loading
Loading