ingest: закрыты мелочи приёма — вырожденное имя, контракт Result, корреляция add
- имя раздачи нормализуется на границе разбора: вырожденное `-` (metainfo.NoName) даёт пустое имя, пробельное схлопывается — сентинел больше не доходит ни до контекста распознавания, ни до source_ref, ни до подсказки вывода имени - контракт «на любом пути ошибки приёма результат нулевой» объявлен в ingest и удерживается структурно; три транспорта перестали обещать идентификатор, которого нет, и коррелируют отказ по request_id - scoped-логгер загрузки ставится до вызова внешнего сервиса в семи командах воркера — записи об отказе qBittorrent и метабаз получили download_id и infohash; граница разбора bencode записана в docs/research
This commit is contained in:
@@ -1035,6 +1035,12 @@ func (w *Worker) Retry(ctx context.Context, id string) (err error) {
|
||||
if d.State != store.StateFailed && d.State != store.StateStuck {
|
||||
return fmt.Errorf("retry: download %s is %s, only failed/stuck are retriable: %w", id, d.State, ErrConflict)
|
||||
}
|
||||
// Scoped-логгер загрузки — ДО первого вызова внешнего сервиса (обязанность
|
||||
// вызывающего, capability identity). Иначе запись клиента qBittorrent об
|
||||
// отказе добавления уходит без download_id/infohash, а причины отказа
|
||||
// qBittorrent не сообщает («Fails.») — корреляция там единственное, что
|
||||
// делает запись пригодной для разбора. Форма та же, что у Delete.
|
||||
ctx = w.scoped(ctx, capReview, id, d.PrimaryInfohash())
|
||||
// Если раздача уже жива и ЗДОРОВА в qBittorrent — перецепляемся к ней,
|
||||
// повторный Add не нужен (и вреден: вслепую дублировал бы торрент). Add — когда
|
||||
// источника в qBittorrent нет. Базис таймаута сбрасывается ниже через
|
||||
@@ -1076,8 +1082,7 @@ func (w *Worker) Retry(ctx context.Context, id string) (err error) {
|
||||
// Байты torrent недоступны — откатываем активацию, задача не должна
|
||||
// «качаться» без раздачи в qBittorrent.
|
||||
if rbErr := w.store.SetDownloadState(ctx, id, d.State, d.ErrorCode.String, d.ErrorMsg.String); rbErr != nil {
|
||||
w.log.Error("retry rollback failed",
|
||||
"capability", capReview, "download_id", id, "error", rbErr)
|
||||
logctx.From(ctx).Error("retry rollback failed", "error", rbErr)
|
||||
}
|
||||
return fmt.Errorf("retry: prepare add: %w", prepErr)
|
||||
}
|
||||
@@ -1085,8 +1090,7 @@ func (w *Worker) Retry(ctx context.Context, id string) (err error) {
|
||||
// Активация уже прошла — откатываем задачу в прежнее состояние,
|
||||
// чтобы не оставить «качающуюся» задачу без раздачи в qBittorrent.
|
||||
if rbErr := w.store.SetDownloadState(ctx, id, d.State, d.ErrorCode.String, d.ErrorMsg.String); rbErr != nil {
|
||||
w.log.Error("retry rollback failed",
|
||||
"capability", capReview, "download_id", id, "error", rbErr)
|
||||
logctx.From(ctx).Error("retry rollback failed", "error", rbErr)
|
||||
}
|
||||
return fmt.Errorf("retry: add to qbittorrent: %w", err)
|
||||
}
|
||||
@@ -1096,8 +1100,7 @@ func (w *Worker) Retry(ctx context.Context, id string) (err error) {
|
||||
// stuck_after на ближайшем тике. Best-effort: сбой лишь лишает свежего окна
|
||||
// (WARN), сам retry уже состоялся.
|
||||
if err := w.store.SetRetriedAt(ctx, id, w.now()); err != nil {
|
||||
w.log.Warn("retry basis reset failed",
|
||||
"capability", capReview, "download_id", id, "error", err)
|
||||
logctx.From(ctx).Warn("retry basis reset failed", "error", err)
|
||||
}
|
||||
// Сброс счётчика пропусков источника: retried source_gone-задача иначе вошла бы
|
||||
// в downloading с source_miss_count == threshold и упала бы снова на ближайшем
|
||||
@@ -1105,11 +1108,10 @@ func (w *Worker) Retry(ctx context.Context, id string) (err error) {
|
||||
// обещанного грейс-окна (MAJOR-3). Best-effort: сбой лишь лишает свежего окна.
|
||||
if d.SourceMissCount != 0 {
|
||||
if err := w.store.SetSourceMissCount(ctx, id, 0); err != nil {
|
||||
w.log.Warn("retry miss count reset failed",
|
||||
"capability", capReview, "download_id", id, "error", err)
|
||||
logctx.From(ctx).Warn("retry miss count reset failed", "error", err)
|
||||
}
|
||||
}
|
||||
logctx.From(w.scoped(ctx, capReview, id, d.PrimaryInfohash())).Info("state transition",
|
||||
logctx.From(ctx).Info("state transition",
|
||||
"from", d.State, "to", store.StateDownloading)
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user