Skip to content

UN-2860 [FIX] Fixed active file cache not preventing duplicate file processing#1570

Merged
harini-venkataraman merged 6 commits into
mainfrom
fix/UN-2860-FIX_active-file-cache-preventing-duplicate-processing
Oct 9, 2025
Merged

UN-2860 [FIX] Fixed active file cache not preventing duplicate file processing#1570
harini-venkataraman merged 6 commits into
mainfrom
fix/UN-2860-FIX_active-file-cache-preventing-duplicate-processing

Conversation

@muhammad-ali-e
Copy link
Copy Markdown
Contributor

What

  • Fixed critical bug where ActiveFileFilter cache checks were failing to detect files already being processed
  • Files from execution A at 15:30 were incorrectly reprocessed by execution B at 16:00 (30 minutes later)
  • Added proper cache data structure access in filter_pipeline.py
  • Increased cache TTL from 1 hour to 2 hours for resource-constrained environments
  • Changed cache status from "EXECUTING" to "PENDING" for queued files
  • Added guaranteed cache cleanup in finally blocks
  • Fixed cache key format consistency between backend and workers
  • Optimized database queries to skip files already found in cache
  • Removed ~370 lines of dead code

Why

  • Root cause: RedisCacheBackend wraps cached data in {data: {...}, cached_at: "...", ttl: 300} but filter_pipeline.py:643 was accessing execution_id directly instead of from the nested data key
  • This caused ALL cache checks to fail silently, returning None for cached_exec_id
  • Without valid cached execution IDs, ActiveFileFilter couldn't identify files already being processed
  • Result: Duplicate file processing in concurrent executions (48 files reprocessed in production logs)
  • Additional issues: Short TTL (5 min) expired before processing started, status "EXECUTING" set too early, no cleanup of stale entries

How

  1. Critical fix in filter_pipeline.py (line 645):

    • Changed cached_data.get("execution_id")cached_data.get("data", {}).get("execution_id")
    • Now correctly extracts execution_id from nested cache structure
  2. Cache lifecycle improvements in active_file_manager.py:

    • Changed status to "PENDING" when files are queued (not "EXECUTING")
    • Increased MAX_ACTIVE_FILE_CACHE_TTL from 3600s to 7200s (1hr → 2hrs)
  3. Guaranteed cache cleanup in file_processing/tasks.py:

    • Added _cleanup_file_cache_entry() helper method
    • Called from finally block to ensure cleanup even on errors
  4. Cache key consistency:

    • Backend now uses hash-based cache keys matching workers
    • Removed redundant cache checks in backend (workers handle filtering)
  5. Database query optimization in filter_pipeline.py:

    • Filter out files found in cache before making database API call
    • Reduces database load when cache is working correctly
  6. Code cleanup:

    • Deleted file_management_utils.py (~150 lines unused)
    • Removed filter_and_cache_files() method (~197 lines unused)
    • Removed _check_database_active_files() method (~23 lines unused)

Can this PR break any existing features. If yes, please list possible items. If no, please explain why.

No, this PR will not break existing features:

  • Cache access fix is backward compatible: The get("data", {}).get("execution_id") pattern safely handles both old and new cache formats (returns None if structure differs)
  • Status change from EXECUTING to PENDING: More accurate status doesn't change behavior - cache entries still prevent duplicate processing
  • TTL increase: Longer cache lifetime only helps prevent false negatives, doesn't affect correctness
  • Cache cleanup improvements: Adding finally blocks ensures cleanup happens more reliably, not less
  • Database query optimization: Only reduces unnecessary queries, doesn't change filtering logic
  • Dead code removal: Removed code wasn't being used anywhere in active execution paths (verified with grep)

Risk mitigation:

  • All changes are additive or corrective (fixing bugs, not changing behavior)
  • Cache key format change maintains same hash-based keys already in use
  • Backend changes only remove redundant checks that workers already perform
  • Optimization preserves exact same filtering logic, just reduces API calls

Database Migrations

  • No database migrations required
  • Changes are only to cache layer (Redis) and in-memory filtering logic

Env Config

  • Optional: Set ACTIVE_FILE_CACHE_TTL to customize cache TTL (default: 300s, max: 7200s)
  • No required configuration changes

Relevant Docs

  • Redis cache structure documented in workers/shared/cache/cache_backends.py
  • Filter pipeline flow documented in workers/shared/processing/filter_pipeline.py
  • Active file management documented in workers/shared/workflow/execution/active_file_manager.py

Related Issues or PRs

Dependencies Versions

  • No dependency version changes
  • Existing Redis and Python dependencies unchanged

Notes on Testing

How to test:

  1. Deploy workflow with file source containing multiple files
  2. Run execution A with max_files=1
  3. Wait 30 seconds (less than DEFAULT_TTL)
  4. Run execution B with max_files=1
  5. Expected: Execution B should process the NEXT file (not the same file as A)
  6. Verify in logs: ActiveFileFilter should log "found 1 from cache" for execution B
  7. Verify in Redis: Check file_active:* keys exist with correct execution IDs

Redis verification:

redis-cli -n 1
keys "file_active:*"
get "file_active:<workflow_id>:<provider_uuid>:<hash>"
# Should show: {"data": {"execution_id": "...", "status": "PENDING", ...}, ...}

Log verification:

[ActiveFileFilter] found 1 from cache for execution <exec_id>
[ActiveFileFilter] Checking 14 remaining files in database (1 already found in cache)

Screenshots

N/A - Backend/worker cache logic fix

Checklist

✅ I have read and understood the Contribution Guidelines.

🤖 Generated with Claude Code

…rocessing

Fixed critical bug where ActiveFileFilter cache checks were failing to detect
files already being processed, causing duplicate file processing in concurrent
workflow executions.

Key fixes:
- Fixed cache data access: Extract execution_id from nested cache structure
  (cached_data["data"]["execution_id"] instead of cached_data["execution_id"])
- Changed cache status from "EXECUTING" to "PENDING" for queued files
- Increased MAX_ACTIVE_FILE_CACHE_TTL from 1hr to 2hrs for resource-constrained environments
- Added cache cleanup in finally blocks to prevent stale entries
- Fixed cache key format consistency (hash-based) between backend and workers
- Optimized DB queries to skip files already found in cache
- Removed ~370 lines of dead code (file_management_utils.py and unused methods)

Root cause: RedisCacheBackend wraps data in {data: {...}, cached_at, ttl} but
filter_pipeline was accessing execution_id directly instead of from nested data key.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Oct 8, 2025

Summary by CodeRabbit

  • New Features
    • Smarter batch processing skips already-active files, reducing unnecessary API work.
  • Performance
    • Faster, more consistent active-file detection via bulk database checks and smaller request payloads.
  • Configuration
    • New env vars: FILE_ACTIVE_CACHE_REDIS_DB and ACTIVE_FILE_CACHE_TTL.
    • Default Redis DB updated to 0; maximum active-file cache TTL increased to 2 hours.
  • Refactor
    • Response payload no longer includes cache hit metrics (cache_hits, cache_hit_rate); cache_stats now reports only db_queries.

Walkthrough

Removed per-file cache lookups in backend active-file checks and replaced them with a single bulk database query (path-aware and UUID-only branches); workers now perform cache-first filtering, submit only remaining composite identifiers to the backend, and always attempt cache cleanup after pre-create attempts; several utility modules and exports were removed and cache TTL/status semantics adjusted.

Changes

Cohort / File(s) Summary
Backend active-file refactor
backend/workflow_manager/internal_views.py
Eliminated cache reads/writes and cache-hit metrics; added a single bulk DB check with path-aware and UUID-only helpers; simplified response to only include db_queries and active identifiers; cleaned up imports and logging.
Worker pre-create cache cleanup
workers/file_processing/tasks.py
Added _cleanup_file_cache_entry and call it from a finally block in _pre_create_file_executions; include execution_id in a log line; cleanup failures are logged (non-fatal).
Worker env
workers/sample.env
Added ACTIVE_FILE_CACHE_TTL=300 and adjusted Redis DB index (CACHE_REDIS_DB updated).
Client logging
workers/shared/clients/file_client.py
Included execution_id in debug/info logs within get_or_create_workflow_file_execution.
Filter pipeline: cache-first + path-aware payloads
workers/shared/processing/filter_pipeline.py
Use ActiveFileManager._create_cache_key and nested cache data (data.execution_id); filter out cached-active files before calling backend; build composite uuid:path payloads for remaining identifiers; handle active_identifiers response with fallback to legacy active_uuids; added tracing logs.
ActiveFileManager changes
workers/shared/workflow/execution/active_file_manager.py
Increased MAX_ACTIVE_FILE_CACHE_TTL to 7200 and enforce capped TTL; changed cache entry status values from EXECUTING to PENDING; removed filter_and_cache_files and DB-check methods (now relies on cache-only skip logic).
Public API surface trim
workers/shared/workflow/execution/__init__.py
Removed FileManagementUtils from __all__ (no longer exported).
Removal: file management utilities
workers/shared/workflow/execution/file_management_utils.py
Deleted module and all public types/classes and orchestration helpers (FileManagementUtils, FileFilterResult, FileLimitResult, LoggerProtocol, etc.).
Backend settings / env
backend/backend/settings/base.py, backend/sample.env
Added FILE_ACTIVE_CACHE_REDIS_DB setting (env-driven, default 0) and FILE_ACTIVE_CACHE_REDIS_DB=0 to sample env.
Cache service: DB-scoped clear
backend/utils/cache_service.py
clear_cache_optimized signature updated to accept optional `db: int
Workflow file history clear
backend/workflow_manager/workflow_v2/file_history_helper.py
clear_history_for_workflow now passes db=settings.FILE_ACTIVE_CACHE_REDIS_DB to CacheService.clear_cache_optimized and logs the DB used.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant W as Worker FilterPipeline
  participant AFM as ActiveFileManager (cache)
  participant API as Backend internal_views
  participant DB as Database

  rect rgb(245,248,255)
  note over W,AFM: Cache-first filtering
  W->>AFM: Create cache keys, read cache entries
  AFM-->>W: Cached-active entries (data.execution_id)
  W->>W: Compute remaining_identifiers (exclude cached-active)
  end

  alt no remaining_identifiers
    W-->>W: Skip backend call
  else remaining_identifiers present
    rect rgb(248,245,255)
    note over W,API: Path-aware bulk query
    W->>API: Request with composite ids (uuid:path)
    API->>DB: Bulk check (path-aware or UUID-only)
    DB-->>API: Active results
    API-->>W: active_identifiers (preferred) or legacy active_uuids
    end
    W->>W: Map response to original identifiers
  end

  note over W: Proceed with non-active files only
Loading
sequenceDiagram
  autonumber
  participant T as Worker Task (_pre_create_file_executions)
  participant C as Cache
  participant L as Logger

  T->>L: Log using file history (includes execution_id)
  rect rgb(245,255,247)
  note over T: Attempt pre-create per file (try)
  T->>T: Create WorkflowFileExecution
  end

  rect rgb(255,249,245)
  note over T,C: Guaranteed cache cleanup (finally)
  T->>C: _cleanup_file_cache_entry(file_hash, workflow_id, file_name)
  C-->>T: Success or error
  T->>L: Warn on cleanup failure (non-fatal)
  end
Loading
sequenceDiagram
  autonumber
  participant API as Backend internal_views
  participant DB as Database

  note over API: Backend no longer reads cache for active-file checks
  API->>DB: Bulk query active files (path-aware or UUID-only)
  DB-->>API: Results
  API->>API: Log db_queries only
  API-->>Caller: { active_identifiers | active_uuids, db_queries }
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly and concisely reflects the primary change by specifying the bug fix for the active file cache that prevented duplicate file processing and aligns directly with the core issue addressed in the pull request.
Description Check ✅ Passed The description adheres to the repository’s template by providing complete sections for What, Why, How, feature impact, database migrations, environment configuration, relevant documentation, related issues, dependencies, testing instructions, screenshots, and the checklist, each filled with detailed and specific information.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/UN-2860-FIX_active-file-cache-preventing-duplicate-processing

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to Reviews > Disable Cache setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 11200cb and 55dcd43.

📒 Files selected for processing (1)
  • backend/sample.env (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/sample.env
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/workflow_manager/internal_views.py (1)

756-767: db_queries count is always set to 2 (inaccurate metrics)

Set db_queries based on whether path-aware and/or legacy queries will actually run.

-                self._bulk_database_check(
+                # Pre-compute which query paths will run
+                has_path = any(f["path"] is not None for f in files_needing_db_check)
+                has_legacy = any(f["path"] is None for f in files_needing_db_check)
+                self._bulk_database_check(
                     files_needing_db_check=files_needing_db_check,
                     workflow_id=workflow_id,
                     current_execution_id=current_execution_id,
                     active_files=active_files,
                     active_identifiers=active_identifiers,
                 )
-                db_queries = 2  # At most 2 bulk queries (path-aware + legacy)
+                db_queries = int(has_path) + int(has_legacy)  # 0–2 depending on paths

Also applies to: 771-772

🧹 Nitpick comments (6)
workers/sample.env (1)

260-262: Add units/bounds note for clarity

ACTIVE_FILE_CACHE_TTL is seconds and capped in code. Consider adding a brief comment (e.g., “seconds, 60–7200”) to avoid misconfiguration.

workers/shared/clients/file_client.py (1)

130-132: Logging additions look good

Including execution_id improves traceability. Consider structured logs (extra=…) for easier filtering downstream.

Also applies to: 223-223, 227-229

backend/workflow_manager/internal_views.py (1)

739-754: Avoid duplicate entries in files_needing_db_check

If input contains repeated uuid/path, we’ll add duplicates and grow Q unnecessarily. Deduplicate by composite_id for performance.

-            for file_data in files:
+            seen = set()
+            for file_data in files:
                 provider_uuid = file_data["uuid"]
                 file_path = file_data.get("path")
                 composite_id = (
                     f"{provider_uuid}:{file_path}" if file_path else provider_uuid
                 )
-
-                # All files need database check
-                files_needing_db_check.append(
+                if composite_id in seen:
+                    continue
+                seen.add(composite_id)
+                files_needing_db_check.append(
                     {
                         "uuid": provider_uuid,
                         "path": file_path,
                         "composite_id": composite_id,
                     }
                 )
workers/file_processing/tasks.py (1)

840-875: Tolerate cleanup errors, but silence BLE001

Catching broad Exception is acceptable in a finally cleanup; annotate to satisfy Ruff BLE001.

-    except Exception as cleanup_error:
+    except Exception as cleanup_error:  # noqa: BLE001
         logger.warning(f"Cache cleanup failed for {file_name}: {cleanup_error}")
         # Don't raise - cache will expire anyway

Please confirm this cleanup timing is intentional: removing the “active” cache right after pre-creating WorkflowFileExecution relies on DB-based active checks to prevent duplicates during processing.

workers/shared/processing/filter_pipeline.py (2)

639-646: Correct: read execution_id from cached_data['data'] and reuse manager key logic

This fixes the root cause and ensures key parity. LGTM.

Prefer a public helper (e.g., ActiveFileManager.create_cache_key) rather than calling a private method (_create_cache_key) across modules to reduce brittleness.


654-656: Consider lowering to debug

This cache-hit count log may be noisy at INFO in high volume pipelines.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to Reviews > Disable Cache setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between f15fe26 and 3111a17.

📒 Files selected for processing (8)
  • backend/workflow_manager/internal_views.py (4 hunks)
  • workers/file_processing/tasks.py (3 hunks)
  • workers/sample.env (1 hunks)
  • workers/shared/clients/file_client.py (2 hunks)
  • workers/shared/processing/filter_pipeline.py (4 hunks)
  • workers/shared/workflow/execution/__init__.py (0 hunks)
  • workers/shared/workflow/execution/active_file_manager.py (3 hunks)
  • workers/shared/workflow/execution/file_management_utils.py (0 hunks)
💤 Files with no reviewable changes (2)
  • workers/shared/workflow/execution/init.py
  • workers/shared/workflow/execution/file_management_utils.py
🧰 Additional context used
🪛 Ruff (0.13.3)
workers/file_processing/tasks.py

872-872: Do not catch blind exception: Exception

(BLE001)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (3)
workers/shared/workflow/execution/active_file_manager.py (1)

421-421: Status PENDING alignment

Changing cache entry status to PENDING is consistent with upstream use. LGTM.

Also applies to: 538-538

workers/file_processing/tasks.py (1)

976-979: Finally cleanup is good; ensure file_hash is always set

file_hash is created before the try, so this is safe. LGTM.

If any early-return paths are added later, ensure file_hash exists to avoid UnboundLocalError.

workers/shared/processing/filter_pipeline.py (1)

660-675: No stale execution_id lookups detected
Repository-wide search found no direct cached_data.get("execution_id") calls. LGTM.

Comment thread workers/shared/workflow/execution/active_file_manager.py
muhammad-ali-e and others added 4 commits October 8, 2025 23:11
Comment thread backend/workflow_manager/internal_views.py
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Oct 9, 2025

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Oct 9, 2025

filepath function $$\textcolor{#23d18b}{\tt{passed}}$$ SUBTOTAL
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_logs}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_cleanup}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_cleanup\_skip}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_client\_init}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_image\_exists}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_image}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_container\_run\_config}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_container\_run\_config\_without\_mount}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_run\_container}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_image\_for\_sidecar}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_sidecar\_container}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{TOTAL}}$$ $$\textcolor{#23d18b}{\tt{11}}$$ $$\textcolor{#23d18b}{\tt{11}}$$

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Oct 9, 2025

filepath function $$\textcolor{#23d18b}{\tt{passed}}$$ SUBTOTAL
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_success\_on\_first\_attempt}}$$ $$\textcolor{#23d18b}{\tt{2}}$$ $$\textcolor{#23d18b}{\tt{2}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_retry\_on\_connection\_error}}$$ $$\textcolor{#23d18b}{\tt{2}}$$ $$\textcolor{#23d18b}{\tt{2}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_non\_retryable\_http\_error}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_retryable\_http\_errors}}$$ $$\textcolor{#23d18b}{\tt{3}}$$ $$\textcolor{#23d18b}{\tt{3}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_post\_method\_retry}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_retry\_logging}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_prompt.py}}$$ $$\textcolor{#23d18b}{\tt{TestPromptToolRetry.test\_success\_on\_first\_attempt}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_prompt.py}}$$ $$\textcolor{#23d18b}{\tt{TestPromptToolRetry.test\_retry\_on\_errors}}$$ $$\textcolor{#23d18b}{\tt{2}}$$ $$\textcolor{#23d18b}{\tt{2}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_prompt.py}}$$ $$\textcolor{#23d18b}{\tt{TestPromptToolRetry.test\_wrapper\_methods\_retry}}$$ $$\textcolor{#23d18b}{\tt{4}}$$ $$\textcolor{#23d18b}{\tt{4}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_connection\_error\_is\_retryable}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_timeout\_is\_retryable}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_http\_error\_retryable\_status\_codes}}$$ $$\textcolor{#23d18b}{\tt{3}}$$ $$\textcolor{#23d18b}{\tt{3}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_http\_error\_non\_retryable\_status\_codes}}$$ $$\textcolor{#23d18b}{\tt{5}}$$ $$\textcolor{#23d18b}{\tt{5}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_http\_error\_without\_response}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_os\_error\_retryable\_errno}}$$ $$\textcolor{#23d18b}{\tt{5}}$$ $$\textcolor{#23d18b}{\tt{5}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_os\_error\_non\_retryable\_errno}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_other\_exception\_not\_retryable}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCalculateDelay.test\_exponential\_backoff\_without\_jitter}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCalculateDelay.test\_exponential\_backoff\_with\_jitter}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCalculateDelay.test\_max\_delay\_cap}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCalculateDelay.test\_max\_delay\_cap\_with\_jitter}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_successful\_call\_first\_attempt}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_retry\_after\_transient\_failure}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_max\_retries\_exceeded}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_max\_time\_exceeded}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_retry\_with\_custom\_predicate}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_no\_retry\_with\_predicate\_false}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_exception\_not\_in\_tuple\_not\_retried}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_delay\_would\_exceed\_max\_time}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_default\_configuration}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_environment\_variable\_configuration}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_invalid\_max\_retries}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_invalid\_max\_time}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_invalid\_base\_delay}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_invalid\_multiplier}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_jitter\_values}}$$ $$\textcolor{#23d18b}{\tt{2}}$$ $$\textcolor{#23d18b}{\tt{2}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_custom\_exceptions\_only}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_custom\_predicate\_only}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_both\_exceptions\_and\_predicate}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_exceptions\_match\_but\_predicate\_false}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestPreconfiguredDecorators.test\_retry\_platform\_service\_call\_exists}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestPreconfiguredDecorators.test\_retry\_prompt\_service\_call\_exists}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestPreconfiguredDecorators.test\_platform\_service\_decorator\_retries\_on\_connection\_error}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestPreconfiguredDecorators.test\_prompt\_service\_decorator\_retries\_on\_timeout}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryLogging.test\_warning\_logged\_on\_retry}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryLogging.test\_info\_logged\_on\_success\_after\_retry}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryLogging.test\_exception\_logged\_on\_giving\_up}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{TOTAL}}$$ $$\textcolor{#23d18b}{\tt{66}}$$ $$\textcolor{#23d18b}{\tt{66}}$$

@harini-venkataraman harini-venkataraman merged commit 0f22474 into main Oct 9, 2025
7 checks passed
@harini-venkataraman harini-venkataraman deleted the fix/UN-2860-FIX_active-file-cache-preventing-duplicate-processing branch October 9, 2025 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants