Skip to content

Conversation

@vishnuszipstack
Copy link
Contributor

@vishnuszipstack vishnuszipstack commented Sep 23, 2025

What

  • HITL Enhancements OSS PR

Why

  • HITL Enhancements

How

  • More details available in cloud PR

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

  • No

Database Migrations

Env Config

Relevant Docs

Related Issues or PRs

Dependencies Versions

Notes on Testing

Screenshots

Checklist

I have read and understood the Contribution Guidelines.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 23, 2025

Summary by CodeRabbit

  • New Features
    • Added Human-In-The-Loop (HITL) workflow support with selectable HITL queue routing across backends.
    • Added HITL file storage type and environment variable support for external storage credentials.
  • Enhancements
    • Propagated organization context to queue operations and improved routing/enqueue logging.
    • Included HITL queue name in queue result payloads to preserve routing downstream.
  • Bug Fixes
    • Broadened accepted MIME types for tool outputs and fixed metadata handling on destination processing errors.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

Adds HITL support: destination propagates organization_id into queue operations and logging; QueueUtils gains HITL routing, lazy dynamic connector imports/caching, and error handling; filesystem adds HITL_FILES storage type and credentials mapping; sample env adds HITL storage credentials.

Changes

Cohort / File(s) Summary
HITL-aware enqueue changes
backend/workflow_manager/endpoint_v2/destination.py
Destination reads organization_id from UserContext, requests a queue with {"use_hitl_backend": True, "organization_id": organization_id}, passes organization_id into packet and regular enqueue/enqueue_with_ttl calls, and expands logging to include organization_id and TTL.
HITL queue selection & connectors
backend/workflow_manager/endpoint_v2/queue_utils.py
Adds HITL flow: class-level _hitl_connectors cache, public get_hitl_queue_inst(backend, connector_settings) and private _import_hitl_connector(connector_name) for lazy dynamic imports of HITL connectors (PostgreSQL/Hybrid). Redis HITL delegates to non-HITL path. Adds structured errors and logging for unknown/missing HITL connectors.
Filesystem HITL storage & env
unstract/filesystem/src/unstract/filesystem/file_storage_types.py, unstract/filesystem/src/unstract/filesystem/file_storage_config.py, backend/sample.env
Adds FileStorageType.HITL_FILES, maps it to StorageType.SHARED_TEMPORARY, adds HITL_FILES_FILE_STORAGE_CREDENTIALS to credential→env mapping, and appends example HITL_FILES_FILE_STORAGE_CREDENTIALS to sample env.
Queue result and connector payloads
workers/shared/models/result_models.py, workers/shared/workflow/destination_connector.py, workers/shared/workflow/execution/service.py
Adds optional hitl_queue_name to QueueResult and includes it in to_dict; propagates hitl_queue_name when enqueuing to manual review; ensures metadata = None on destination processing exceptions to guarantee file history creation.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant Destination as endpoint_v2.destination
  participant QueueUtils
  participant HITLConnector as HITL_Connector
  participant Queue as Queue_Instance

  Client->>Destination: enqueue request
  Destination->>Destination: resolve organization_id (UserContext)
  Destination->>QueueUtils: get_queue_inst({use_hitl_backend: true, organization_id})
  alt HITL path
    QueueUtils->>QueueUtils: get_hitl_queue_inst(backend, settings)
    alt backend == PostgreSQL or Hybrid
      QueueUtils->>QueueUtils: _import_hitl_connector(name)
      QueueUtils->>HITLConnector: instantiate(settings)
      HITLConnector-->>QueueUtils: return Queue_Instance
    else backend == Redis
      QueueUtils->>QueueUtils: clear HITL flag and delegate to standard get_queue_inst
    else unknown/missing
      QueueUtils-->>Destination: raise UnstractQueueException
    end
  else non-HITL path
    QueueUtils->>QueueUtils: standard get_queue_inst flow
  end
  QueueUtils-->>Destination: Queue_Instance
  Destination->>Queue: enqueue(payload, ttl?, actor_id=None, organization_id)
  Queue-->>Destination: enqueue result
  Destination-->>Client: acknowledgement
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The description is largely incomplete with vague explanations (e.g., 'More details available in cloud PR') and missing critical details like testing notes, env config details, and specific HITL changes despite substantial code modifications. Expand the description with specific details about HITL queue routing, file storage mapping changes, and testing approach; clarify the env config changes needed and update relevant sections rather than deferring to external PRs.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title specifically references moving away from Redis HITL file handling, which aligns with the changeset's focus on introducing HITL enhancements with queue management and file storage configuration updates.
Docstring Coverage ✅ Passed Docstring coverage is 91.67% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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
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: 2

🧹 Nitpick comments (4)
unstract/filesystem/src/unstract/filesystem/file_storage_config.py (1)

31-32: Confirm SHARED_TEMPORARY aligns with HITL data handling.

If HITL artifacts may include PII, confirm SHARED_TEMPORARY meets isolation, retention, and encryption expectations; otherwise consider a dedicated storage tier/bucket/namespace.

backend/workflow_manager/endpoint_v2/queue_utils.py (3)

28-41: Avoid mutable default for connector_settings

Use None default and initialize inside to satisfy linters and prevent shared state.

-    def get_queue_inst(connector_settings: dict[str, Any] = {}) -> UnstractQueue:
+    def get_queue_inst(connector_settings: dict[str, Any] | None = None) -> UnstractQueue:
+        if connector_settings is None:
+            connector_settings = {}
         """Get queue connector instance based on configuration.

53-56: Avoid mutable default for connector_settings (HITL path)

Same fix for get_hitl_queue_inst.

-    def get_hitl_queue_inst(
-        backend: str, connector_settings: dict[str, Any] = {}
-    ) -> UnstractQueue:
+    def get_hitl_queue_inst(
+        backend: str, connector_settings: dict[str, Any] | None = None
+    ) -> UnstractQueue:
+        if connector_settings is None:
+            connector_settings = {}

95-109: Prefer logger.exception and preserve traceback with from e

Improves observability and complies with linter hints.

-        except ImportError as e:
-            logger.error(
-                f"HITL queue backend '{backend}' not available: {e}. "
-                f"Make sure 'pluggable_apps.manual_review_v2' is installed and configured."
-            )
-            raise UnstractQueueException(
-                detail=f"HITL queue backend '{backend}' not available. "
-                f"Please install the manual_review_v2 app or use 'redis' backend."
-            )
-        except Exception as e:
-            logger.error(f"Failed to initialize HITL queue backend '{backend}': {e}")
-            raise UnstractQueueException(
-                detail=f"Failed to initialize HITL queue backend '{backend}': {str(e)}"
-            )
+        except ImportError as e:
+            logger.exception(
+                "HITL queue backend '%s' not available: %s. Make sure 'pluggable_apps.manual_review_v2' is installed and configured.",
+                backend, e
+            )
+            raise UnstractQueueException(
+                detail=f"HITL queue backend '{backend}' not available. "
+                f"Please install the manual_review_v2 app or use 'redis' backend."
+            ) from e
+        except Exception as e:
+            logger.exception("Failed to initialize HITL queue backend '%s': %s", backend, e)
+            raise UnstractQueueException(
+                detail=f"Failed to initialize HITL queue backend '{backend}': {str(e)}"
+            ) from e
📜 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 51bea4e and c41d334.

📒 Files selected for processing (4)
  • backend/workflow_manager/endpoint_v2/destination.py (2 hunks)
  • backend/workflow_manager/endpoint_v2/queue_utils.py (4 hunks)
  • unstract/filesystem/src/unstract/filesystem/file_storage_config.py (1 hunks)
  • unstract/filesystem/src/unstract/filesystem/file_storage_types.py (1 hunks)
🧰 Additional context used
🪛 Ruff (0.13.1)
backend/workflow_manager/endpoint_v2/queue_utils.py

54-54: Do not use mutable data structures for argument defaults

Replace with None; initialize within function

(B006)


96-99: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


100-103: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


104-104: Do not catch blind exception: Exception

(BLE001)


105-105: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


106-108: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


107-107: Use explicit conversion flag

Replace with conversion flag

(RUF010)


141-143: Avoid specifying long messages outside the exception class

(TRY003)


147-149: Avoid specifying long messages outside the exception class

(TRY003)

⏰ 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 (2)
unstract/filesystem/src/unstract/filesystem/file_storage_types.py (1)

7-7: Add brief usage note or doc where this enum is documented.

LGTM. Please ensure HITL_FILES is referenced in any docs/samples that enumerate FileStorageType values.

backend/workflow_manager/endpoint_v2/destination.py (1)

802-816: Verify HITL queue connector API supports enqueue_with_ttl; prefer self.organization_id

  • UnstractQueue does not declare enqueue_with_ttl and the repo has no implementations — confirm pluggable HITL connectors (HybridQueue/PostgreSQLQueue) expose enqueue_with_ttl(queue_name, message, ttl_seconds=None, actor_id=None) or add the method/guard the call to avoid AttributeError.
  • Replace re-fetch of org id with self.organization_id in backend/workflow_manager/endpoint_v2/destination.py (occurrences near lines ~803 and ~864):
-            organization_id = UserContext.get_organization_identifier()
+            organization_id = self.organization_id

@vishnuszipstack vishnuszipstack changed the title Un 2663 moving away from redis hitl file handling improvements UN-2663 [FEAT] moving away from redis hitl file handling improvements Sep 23, 2025
Copy link
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

🧹 Nitpick comments (1)
backend/workflow_manager/endpoint_v2/queue_utils.py (1)

54-78: Avoid mutable default for connector_settings

Using {} as a default argument means every call without an explicit settings dict shares the same object, which can lead to surprising cross-call mutations if a connector modifies the dict. Please default to None and instantiate inside the function.

-        backend: str, connector_settings: dict[str, Any] = {}
+        backend: str, connector_settings: dict[str, Any] | None = None
     ) -> UnstractQueue:
@@
-        if backend == "redis":
+        connector_settings = connector_settings or {}
+        if backend == "redis":
             # Strip HITL flag to force default (non-HITL) connector path
             non_hitl_settings = dict(connector_settings)

Based on static analysis hints.

📜 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 c41d334 and 047e601.

📒 Files selected for processing (2)
  • backend/sample.env (1 hunks)
  • backend/workflow_manager/endpoint_v2/queue_utils.py (3 hunks)
🧰 Additional context used
🪛 Ruff (0.13.1)
backend/workflow_manager/endpoint_v2/queue_utils.py

25-25: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)


28-28: Do not use mutable data structures for argument defaults

Replace with None; initialize within function

(B006)


54-54: Do not use mutable data structures for argument defaults

Replace with None; initialize within function

(B006)


99-102: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


103-106: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


107-107: Do not catch blind exception: Exception

(BLE001)


108-108: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


109-111: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


110-110: Use explicit conversion flag

Replace with conversion flag

(RUF010)


142-144: Avoid specifying long messages outside the exception class

(TRY003)


148-150: Avoid specifying long messages outside the exception class

(TRY003)

⏰ 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 (1)
backend/sample.env (1)

204-204: LGTM: HITL storage credentials sample entry

Thanks for wiring up the sample credentials; this keeps the sample env aligned with the new HITL_FILES storage configuration.

Copy link
Contributor

@chandrasekharan-zipstack chandrasekharan-zipstack left a comment

Choose a reason for hiding this comment

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

NIT comments can be resolved later

Copy link
Contributor

@jaseemjaskp jaseemjaskp left a comment

Choose a reason for hiding this comment

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

LGTM

…dling-improvements

Signed-off-by: vishnuszipstack <117254672+vishnuszipstack@users.noreply.github.com>
@github-actions
Copy link
Contributor

github-actions bot commented Oct 6, 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}}$$

Copy link
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: 2

🧹 Nitpick comments (1)
backend/sample.env (1)

204-204: Consider adding a documentation comment.

The new HITL_FILES_FILE_STORAGE_CREDENTIALS environment variable lacks an explanatory comment. Adding a brief comment (similar to those for other sections like "X2Text Service" or "Prompt Studio") would improve clarity for developers.

Example:

+# HITL (Human-In-The-Loop) Files Storage
 HITL_FILES_FILE_STORAGE_CREDENTIALS='{"provider": "minio", "credentials": {"endpoint_url": "http://unstract-minio:9000", "key": "minio", "secret": "minio123"}}'

Operational note: While reusing the same MinIO instance and credentials is appropriate for this sample configuration, production deployments should consider isolating HITL file storage with separate credentials or dedicated storage to enhance security boundaries and enable independent scaling/lifecycle management.

📜 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 b585759 and fd17def.

📒 Files selected for processing (2)
  • backend/sample.env (1 hunks)
  • backend/workflow_manager/endpoint_v2/destination.py (2 hunks)
⏰ 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

@sonarqubecloud
Copy link

@sonarqubecloud
Copy link

sonarqubecloud bot commented Dec 5, 2025

Copy link
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: 3

🤖 Fix all issues with AI agents
In @backend/workflow_manager/endpoint_v2/queue_utils.py:
- Line 54: The function parameter uses a mutable default (connector_settings:
dict[str, Any] = {}) which can cause shared-state bugs; change the signature to
accept connector_settings: Optional[dict[str, Any]] = None (add typing.Optional
import) and inside the function set connector_settings = {} if
connector_settings is None; apply the same change to the related get_queue_inst
function if it has the same pattern so both use None-check initialization.
- Line 28: The function get_queue_inst currently uses a mutable default
connector_settings: dict[str, Any] = {}, which can lead to shared-state bugs;
change the signature to accept connector_settings: dict[str, Any] | None = None
(or Optional[dict[str, Any]] = None) and inside get_queue_inst set
connector_settings = connector_settings or {} before using it so each call gets
a fresh dict; update any callers or tests if they relied on the old default
behavior.
- Around line 24-25: The class-level mutable registry _hitl_connectors should be
annotated as a typing.ClassVar[dict] and protected with a class-level
threading.Lock to avoid race conditions during lazy initialization; add a
ClassVar lock (e.g., _hitl_connectors_lock) and in _import_hitl_connector and
get_queue_inst wrap reads/writes to _hitl_connectors with that lock (acquire
before checking/initializing an entry and release after), ensuring only one
thread performs the import/assignment while others wait.
🧹 Nitpick comments (2)
backend/workflow_manager/endpoint_v2/queue_utils.py (2)

98-111: Improve exception handling patterns.

The exception handling can be enhanced by following Python best practices:

  1. Use logging.exception instead of logging.error for exceptions (provides automatic traceback)
  2. Chain exceptions with from e or from None to preserve exception context
  3. The broad Exception catch is acceptable here but could be more specific
♻️ Proposed improvements
     except ImportError as e:
-        logger.error(
+        logger.exception(
             f"HITL queue backend '{backend}' not available: {e}. "
             f"Make sure 'pluggable_apps.manual_review_v2' is installed and configured."
         )
         raise UnstractQueueException(
             detail=f"HITL queue backend '{backend}' not available. "
             f"Please install the manual_review_v2 app or use 'redis' backend."
-        )
+        ) from e
     except Exception as e:
-        logger.error(f"Failed to initialize HITL queue backend '{backend}': {e}")
+        logger.exception(f"Failed to initialize HITL queue backend '{backend}'")
         raise UnstractQueueException(
-            detail=f"Failed to initialize HITL queue backend '{backend}': {str(e)}"
-        )
+            detail=f"Failed to initialize HITL queue backend '{backend}': {e!s}"
+        ) from e

Based on static analysis hints.


141-150: Consider extracting exception messages to constants (optional).

The static analysis suggests avoiding long inline exception messages. While the current approach is acceptable and provides context-specific messages, you could optionally extract these to constants or the exception class for better maintainability.

♻️ Optional refactor

At the top of the file:

# HITL error messages
_HITL_CONNECTORS_NOT_AVAILABLE = (
    "HITL connectors not available. "
    "Make sure 'pluggable_apps.manual_review_v2' is installed."
)
_HITL_CONNECTOR_UNKNOWN_FMT = (
    "Unknown HITL connector: {connector}. Available: {available}"
)

Then use in the method:

     if not cls._hitl_connectors:
-        raise ImportError(
-            "HITL connectors not available. Make sure 'pluggable_apps.manual_review_v2' is installed."
-        )
+        raise ImportError(_HITL_CONNECTORS_NOT_AVAILABLE)
 
     if connector_name not in cls._hitl_connectors:
         available_connectors = list(cls._hitl_connectors.keys())
-        raise ImportError(
-            f"Unknown HITL connector: {connector_name}. Available: {available_connectors}"
-        )
+        raise ImportError(
+            _HITL_CONNECTOR_UNKNOWN_FMT.format(
+                connector=connector_name, 
+                available=available_connectors
+            )
+        )

Based on static analysis hints, though the current inline approach is also acceptable.

📜 Review details

Configuration used: Organization 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 877d805 and fb92521.

📒 Files selected for processing (3)
  • backend/sample.env
  • backend/workflow_manager/endpoint_v2/destination.py
  • backend/workflow_manager/endpoint_v2/queue_utils.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/workflow_manager/endpoint_v2/destination.py
  • backend/sample.env
🧰 Additional context used
🧬 Code graph analysis (1)
backend/workflow_manager/endpoint_v2/queue_utils.py (2)
unstract/connectors/src/unstract/connectors/queues/unstract_queue.py (1)
  • UnstractQueue (9-136)
backend/workflow_manager/endpoint_v2/exceptions.py (1)
  • UnstractQueueException (106-113)
🪛 Ruff (0.14.10)
backend/workflow_manager/endpoint_v2/queue_utils.py

25-25: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)


28-28: Do not use mutable data structures for argument defaults

Replace with None; initialize within function

(B006)


54-54: Do not use mutable data structures for argument defaults

Replace with None; initialize within function

(B006)


99-102: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


103-106: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


107-107: Do not catch blind exception: Exception

(BLE001)


108-108: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


109-111: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


110-110: Use explicit conversion flag

Replace with conversion flag

(RUF010)


142-144: Avoid specifying long messages outside the exception class

(TRY003)


148-150: Avoid specifying long messages outside the exception class

(TRY003)

⏰ 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 (1)
backend/workflow_manager/endpoint_v2/queue_utils.py (1)

89-96: Verify unknown backend fallback behavior.

When an unknown HITL backend is specified, the code logs a warning but silently falls back to hybrid. This could mask configuration errors (e.g., typos like "postgersql"). Consider whether failing fast would be more appropriate, or if the graceful degradation is intentional for forward compatibility.

You may want to verify this behavior aligns with your operational requirements. If strict validation is preferred, consider raising an exception instead of falling back.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 3, 2026

Test Results

Summary
  • Runner Tests: 11 passed, 0 failed (11 total)
  • SDK1 Tests: 66 passed, 0 failed (66 total)

Runner Tests - Full Report
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}}$$
SDK1 Tests - Full Report
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}}$$

@sonarqubecloud
Copy link

sonarqubecloud bot commented Feb 3, 2026

@athul-rs athul-rs merged commit 38b3ce1 into main Feb 3, 2026
7 checks passed
@athul-rs athul-rs deleted the UN-2663-moving-away-from-redis-hitl-file-handling-improvements branch February 3, 2026 12:20
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.

5 participants