Skip to content

UN-2850 [FIX] Add INPROGRESS notification for scheduled ETL executions and adjust status mapping#1562

Merged
ritwik-g merged 2 commits into
mainfrom
fix/UN-2850-FIX_Update_ETL_webhook_response_status_change
Oct 8, 2025
Merged

UN-2850 [FIX] Add INPROGRESS notification for scheduled ETL executions and adjust status mapping#1562
ritwik-g merged 2 commits into
mainfrom
fix/UN-2850-FIX_Update_ETL_webhook_response_status_change

Conversation

@muhammad-ali-e
Copy link
Copy Markdown
Contributor

@muhammad-ali-e muhammad-ali-e commented Oct 6, 2025

What

  • Worker V2 Fixes
  • Added support for INPROGRESS notification status for scheduled ETL executions
  • Added SCHEDULED_EXECUTION as a new notification source
  • Fixed notification status mapping for backward compatibility between API and ETL workflows
  • Updated Slack webhook message formatting to inline format
  • Standardized key naming in Slack notifications

Why

  • Scheduled ETL executions need to send notifications when they start (INPROGRESS status)
  • Different workflow types (API vs ETL/TASK) require different status mappings for backward compatibility
  • Improved Slack message readability with inline formatting
  • Consistent key naming across notification messages

How

  • Extended NotificationStatus enum with INPROGRESS
  • Extended NotificationSource enum with SCHEDULED_EXECUTION
  • Added conditional logic in NotificationPayload to map COMPLETED to SUCCESS for non-API workflows
  • Modified Slack webhook blocks to use inline text format
  • Implemented notification trigger in scheduler when pipeline status changes to INPROGRESS

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. Changes maintain backward compatibility:

  • API workflows continue using COMPLETED status as before
  • ETL/TASK workflows now correctly use SUCCESS status (fixing previous inconsistency)
  • New INPROGRESS status is additive and only used for scheduled executions
  • Notification infrastructure remains unchanged, only payload structure enhanced

Database Migrations

  • No database migrations required

Env Config

  • No environment configuration changes required

Relevant Docs

  • Related to webhook notification system
  • Impacts scheduled execution workflows

Related Issues or PRs

  • Jira: UN-2850

Dependencies Versions

  • No dependency changes

Notes on Testing

  • Test scheduled ETL execution triggers INPROGRESS notification
  • Verify API workflows still use COMPLETED status
  • Verify ETL/TASK workflows use SUCCESS status
  • Check Slack webhook formatting displays inline
  • Validate notification is sent at pipeline start

Screenshots

N/A

Checklist

I have read and understood the Contribution Guidelines.

🤖 Generated with Claude Code

… executions

- Add INPROGRESS status to NotificationStatus enum for scheduled executions
- Add SCHEDULED_EXECUTION source to NotificationSource enum
- Fix notification status mapping for backward compatibility:
  - API workflows use COMPLETED status
  - ETL/TASK workflows use SUCCESS status
- Update Slack webhook formatting to inline display
- Standardize key naming in Slack notifications (ID → Id)
- Trigger INPROGRESS notification when scheduled pipeline starts

🤖 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 6, 2025

Summary by CodeRabbit

  • New Features

    • Sends IN PROGRESS notifications when pipelines start, including scheduled runs.
    • Adds “scheduled-execution” as a notification source.
  • Bug Fixes

    • Keeps completed non-API workflows labeled as SUCCESS for consistency.
    • Improves resilience: notification issues are logged and no longer interrupt workflows.
  • Style

    • Slack webhook messages use single-line fields for clearer readability.
    • Retains original label casing for “Execution Id” and “Organization Id.”

Walkthrough

Adds INPROGRESS status and scheduled-execution source to core models, changes final COMPLETED mapping to SUCCESS for non-API workflows, tweaks Slack block formatting and key casing, and integrates guarded scheduler-side notification dispatches for INPROGRESS events.

Changes

Cohort / File(s) Summary
Core data models update
unstract/core/src/unstract/core/data_models.py
Added NotificationStatus.INPROGRESS and NotificationSource.SCHEDULED_EXECUTION. Adjusted NotificationPayload.from_execution_status so COMPLETED maps to COMPLETED only for API workflows; otherwise maps to SUCCESS. No signature changes.
Slack notification formatting
workers/notification/providers/slack_webhook.py
Changed section text formatting from multiline ("*{key}:*\n{value}") to inline ("*{key}:* {value}"). Retained original casing for Execution Id and Organization Id (removed normalization to ID).
Scheduler notification integration
workers/scheduler/tasks.py
Added _send_pipeline_status_notification(...) helper to build NotificationPayload and call trigger_notification, handling validation and send errors without raising. Calls added when pipelines transition to INPROGRESS in execute_pipeline_task_v2 and _execute_scheduled_workflow. Added imports and logging.
Notification dispatch helper
workers/shared/patterns/notification/helper.py
Added trigger_notification(api_client, pipeline_id, pipeline_name, notification_payload) to fetch pipeline notification configs, filter active entries, and send WEBHOOK-type notifications via send_notification_to_worker, with broad exception handling and logging.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Scheduler as Scheduler Task
  participant API as API Client
  participant Notify as Notification Helper
  participant Slack as Slack Provider

  rect rgb(240,248,255)
    note over Scheduler: Pipeline transitions to INPROGRESS
    Scheduler->>API: update_pipeline_status(INPROGRESS)
    Scheduler->>Scheduler: _send_pipeline_status_notification(...)
  end

  rect rgb(245,255,250)
    note over Scheduler: Build NotificationPayload (source may be scheduled-execution)
    Scheduler->>Notify: trigger_notification(pipeline_id, name, payload)
    alt Active WEBHOOK notifications found
      Notify->>Slack: send_notification_to_worker(webhook, payload with inline blocks)
      Slack-->>Notify: 2xx / success
      Notify-->>Scheduler: returned (logged success)
    else No active WEBHOOKs or non-WEBHOOK
      Notify-->>Scheduler: no-op (logged)
    end
    alt Errors during dispatch
      Notify-->>Scheduler: error (logged, not raised)
    end
  end
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 succinctly captures the main changes of this pull request by specifying the addition of INPROGRESS notifications for scheduled ETL executions and the adjustment of status mapping, making it clear and specific for someone scanning the history.
Description Check ✅ Passed The pull request description fully adheres to the repository template by including and populating all required sections (What, Why, How, impact assessment, migrations, config, docs, related issues, testing notes, and checklist), providing complete context and details for reviewers.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ 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-2850-FIX_Update_ETL_webhook_response_status_change

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

Caution

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

⚠️ Outside diff range comments (1)
workers/notification/providers/slack_webhook.py (1)

117-127: Timestamp labeled UTC but not using UTC

datetime.now() is local time; message says UTC. Use timezone-aware UTC.

Apply:

-            from datetime import datetime
+            from datetime import datetime, timezone
@@
-                            "text": f"_Sent at {datetime.now().strftime('%Y-%m-%d %H:%M:%S UTC')}_",
+                            "text": f"_Sent at {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')}_",
🧹 Nitpick comments (3)
workers/notification/providers/slack_webhook.py (1)

182-184: Key normalization change OK; optional: keep “ID” uppercase

If desired, map to “Execution ID” / “Organization ID” for consistency with common acronyms. Not blocking.

workers/scheduler/tasks.py (1)

35-91: Non-fatal notification helper is good; add stack traces and avoid blind excepts

Keep behavior, but log exceptions with stack traces for debuggability.

Apply:

-    except Exception as notification_error:
-        logger.warning(
-            f"Failed to send notification for {pipeline_type} {pipeline_id}: {notification_error}"
-        )
+    except Exception as notification_error:
+        logger.warning(
+            f"Failed to send notification for {pipeline_type} {pipeline_id}: {notification_error}",
+            exc_info=True,
+        )

Optional: type the signature as

  • pipeline_type: WorkflowType | str
  • status: NotificationStatus | str
    and validate before constructing NotificationPayload (keeps failures localized).
unstract/core/src/unstract/core/data_models.py (1)

591-596: COMPLETED mapping change is correct; add tests and optional EXECUTING support

  • Back-compat mapping (API→COMPLETED, ETL/TASK→SUCCESS) is correct.
  • NotificationPayload.from_execution_status still rejects PENDING/EXECUTING – consider an optional flag to map EXECUTING→IN_PROGRESS.
  • Add/confirm unit tests for:
    • API: COMPLETED→COMPLETED
    • ETL/TASK: COMPLETED→SUCCESS
    • EXECUTING: ValueError (current behavior)
  • Call sites in workers/shared/patterns/notification/helper.py (lines 151–155, 224–228, 336–340)
  • Also applies to data_models.py lines 601–604
📜 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 e6b8e94 and 29a8bf4.

📒 Files selected for processing (3)
  • unstract/core/src/unstract/core/data_models.py (3 hunks)
  • workers/notification/providers/slack_webhook.py (2 hunks)
  • workers/scheduler/tasks.py (3 hunks)
🧰 Additional context used
🪛 Ruff (0.13.3)
workers/scheduler/tasks.py

86-86: 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 (4)
unstract/core/src/unstract/core/data_models.py (2)

476-477: INPROGRESS status addition looks good

Enum extension aligns with scheduled execution notifications.


491-492: New source SCHEDULED_EXECUTION approved

Matches scheduler usage for INPROGRESS notifications.

workers/notification/providers/slack_webhook.py (1)

104-111: Inline block formatting LGTM

More compact Slack messages without losing readability.

workers/scheduler/tasks.py (1)

314-323: Approve INPROGRESS emission location
Parameters are correct and pipeline_type values are constrained by the client and model to valid WorkflowType enums (invalid values simply log a warning and default to API). No changes needed.

@muhammad-ali-e muhammad-ali-e changed the title UN-2850 [FIX] Update ETL webhook response status change for scheduled executions UN-2850 [FIX] Add INPROGRESS notification for scheduled ETL executions and adjust status mapping Oct 6, 2025
@github-actions
Copy link
Copy Markdown
Contributor

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

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Oct 7, 2025

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

🧹 Nitpick comments (3)
workers/shared/patterns/notification/helper.py (3)

102-107: Add type hint for api_client parameter.

The api_client parameter lacks a type annotation, which reduces code clarity and prevents type checkers from validating its usage.

Consider adding the appropriate type hint:

 def trigger_notification(
-    api_client,
+    api_client: "APIClient",  # or the actual type
     pipeline_id: str,
     pipeline_name: str,
     notification_payload: NotificationPayload,
 ) -> None:

102-155: Consider extracting common notification logic to reduce duplication.

This new function shares substantial logic with trigger_pipeline_notifications (lines 157-241) and trigger_api_notifications (lines 243-313):

  • API call to fetch notifications (lines 115-119)
  • Filtering active notifications (lines 124-126)
  • Webhook sending loop (lines 137-151)

Extracting the shared notification fetching and dispatching logic into a helper function would improve maintainability and reduce the risk of inconsistencies.

Example refactor:

def _fetch_and_send_notifications(
    api_client,
    endpoint: str,
    entity_id: str,
    entity_name: str,
    payload: NotificationPayload,
) -> None:
    """Shared logic for fetching and sending notifications."""
    try:
        response_data = api_client._make_request(
            method="GET",
            endpoint=endpoint,
            timeout=10,
        )
        
        notifications_data = response_data.get("notifications", [])
        active_notifications = [
            n for n in notifications_data if n.get("is_active", False)
        ]
        
        if not active_notifications:
            logger.info(f"No active notifications found for {entity_name}")
            return
            
        logger.info(
            f"Sending {len(active_notifications)} notifications for {entity_name}"
        )
        
        for notification in active_notifications:
            if notification.get("notification_type") == "WEBHOOK":
                send_notification_to_worker(
                    url=notification["url"],
                    payload=payload,
                    auth_type=notification.get("authorization_type", "NONE"),
                    auth_key=notification.get("authorization_key"),
                    auth_header=notification.get("authorization_header"),
                    max_retries=notification.get("max_retries", 0),
                    platform=notification.get("platform"),
                )
            else:
                logger.debug(
                    f"Skipping non-webhook notification type: {notification.get('notification_type')}"
                )
                
    except Exception as e:
        logger.exception(f"Error sending notifications for {entity_name}: {e}")


def trigger_notification(
    api_client,
    pipeline_id: str,
    pipeline_name: str,
    notification_payload: NotificationPayload,
) -> None:
    """Trigger notifications for pipeline status updates."""
    _fetch_and_send_notifications(
        api_client=api_client,
        endpoint=f"v1/webhook/pipeline/{pipeline_id}/notifications/",
        entity_id=pipeline_id,
        entity_name=pipeline_name,
        payload=notification_payload,
    )

153-154: Use logging.exception for better error diagnostics.

Replace logging.error with logging.exception to automatically include the stack trace, which aids in debugging.

As per static analysis:

     except Exception as e:
-        logger.error(f"Error triggering pipeline notifications for {pipeline_id}: {e}")
+        logger.exception(f"Error triggering pipeline notifications for {pipeline_id}: {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 29a8bf4 and 71b1848.

📒 Files selected for processing (1)
  • workers/shared/patterns/notification/helper.py (1 hunks)
🧰 Additional context used
🪛 Ruff (0.13.3)
workers/shared/patterns/notification/helper.py

153-153: Do not catch blind exception: Exception

(BLE001)


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

Replace with exception

(TRY400)

⏰ 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

@ritwik-g ritwik-g merged commit 26f423c into main Oct 8, 2025
7 checks passed
@ritwik-g ritwik-g deleted the fix/UN-2850-FIX_Update_ETL_webhook_response_status_change branch October 8, 2025 06:15
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