Tencent/WeKnora · error

failed to get FAQ import progress from Redis

Error message

failed to get FAQ import progress from Redis: %w

What it means

GetFAQImportProgress wraps errors from reading the FAQ import progress document in Redis (keyed by taskID), except for redis.Nil which is converted to a NotFoundError. Any other Redis failure (connection refused, timeout, cluster error) is wrapped here, so callers cannot fetch task status.

Solutions

  1. Check Redis health and connectivity from the service (PING, logs)
  2. Verify REDIS_URL/password configuration for the environment
  3. Retry the progress query; transient Redis errors usually clear after failover
  4. If the task also vanished (redis.Nil -> 404), re-run the import or check task TTL settings

Example fix

// before
data, err := s.redisClient.Get(ctx, key).Bytes()
if err != nil {
	if errors.Is(err, redis.Nil) {
		return nil, werrors.NewNotFoundError("FAQ import task not found")
	}
	return nil, fmt.Errorf("failed to get FAQ import progress from Redis: %w", err)
}
// after
data, err := s.redisClient.Get(ctx, key).Bytes()
if err != nil {
	if errors.Is(err, redis.Nil) {
		return nil, werrors.NewNotFoundError("FAQ import task not found")
	}
	return nil, fmt.Errorf("failed to get FAQ import progress from Redis (task %s): %w", taskID, err)
}
Defensive patterns

Strategy: retry

Validate before calling

// Polling client: check Redis reachability before querying task progress
if err := redisClient.Ping(ctx).Err(); err != nil {
	return nil, fmt.Errorf("progress store unavailable: %w", err)
}

Try / catch

progress, err := svc.GetFAQImportProgress(ctx, taskID)
if err != nil {
	if strings.Contains(err.Error(), "failed to get FAQ import progress from Redis") {
		// transient Redis error: retry with backoff, then surface 503
		if p, rerr := retryWithBackoff(3, svc.GetFAQImportProgress, ctx, taskID); rerr == nil {
			return p, nil
		}
		return nil, statusServiceUnavailable("progress store temporarily unavailable")
	}
	if isNotFound(err) {
		return nil, statusNotFound("FAQ import task not found")
	}
	return nil, err
}

Prevention

When it happens

Trigger: Client polls GET progress for a task; Redis GET fails due to connection loss, read-only replica, OOM, or timeout. A missing key deliberately returns the NotFoundError instead of this error.

Common situations: Redis restart/failover mid-import; wrong REDIS_URL or auth in env; progress key expired (TTL) would be redis.Nil -> 404, but network errors produce this message; Redis maxmemory evictions breaking reads.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/c487e2a70100f3c7. Report an issue: GitHub.

Appendix: source

Thrown at internal/application/service/knowledge_faq_import.go:2771

	}
	return s.redisClient.Set(ctx, key, data, faqImportProgressTTL).Err()
}

// GetFAQImportProgress retrieves the progress of an FAQ import task
func (s *knowledgeService) GetFAQImportProgress(ctx context.Context, taskID string) (*types.FAQImportProgress, error) {
	if s.redisClient == nil {
		if v, ok := s.memFAQProgress.Load(taskID); ok {
			return v.(*types.FAQImportProgress), nil
		}
		return nil, werrors.NewNotFoundError("FAQ import task not found")
	}
	key := getFAQImportProgressKey(taskID)
	data, err := s.redisClient.Get(ctx, key).Bytes()
	if err != nil {
		if errors.Is(err, redis.Nil) {
			return nil, werrors.NewNotFoundError("FAQ import task not found")
		}
		return nil, fmt.Errorf("failed to get FAQ import progress from Redis: %w", err)
	}

	var progress types.FAQImportProgress
	if err := json.Unmarshal(data, &progress); err != nil {
		return nil, fmt.Errorf("failed to unmarshal FAQ import progress: %w", err)
	}

	// If task is completed, enrich with persisted result fields from database
	if progress.Status == types.FAQImportStatusCompleted && progress.KnowledgeID != "" {
		tenantID := ctx.Value(types.TenantIDContextKey).(uint64)
		knowledge, err := s.repo.GetKnowledgeByID(ctx, tenantID, progress.KnowledgeID)
		if err == nil && knowledge != nil {
			if result, err := knowledge.GetLastFAQImportResult(); err == nil && result != nil {
				progress.SuccessCount = result.SuccessCount
				progress.FailedCount = result.FailedCount
				progress.PartialFailedCount = result.PartialFailedCount
				progress.SkippedCount = result.SkippedCount
				progress.MergedCount = result.MergedCount

View on GitHub (pinned to 988cbb0330)