Skip to content

Commit

Permalink
Add connector deletion failure message (#2392)
Browse files Browse the repository at this point in the history
  • Loading branch information
pablonyx authored Sep 12, 2024
1 parent f69922f commit 58bdf9d
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""add ccpair deletion failure message
Revision ID: 0ebb1d516877
Revises: 52a219fb5233
Create Date: 2024-09-10 15:03:48.233926
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = "0ebb1d516877"
down_revision = "52a219fb5233"
branch_labels = None
depends_on = None


def upgrade() -> None:
op.add_column(
"connector_credential_pair",
sa.Column("deletion_failure_message", sa.String(), nullable=True),
)


def downgrade() -> None:
op.drop_column("connector_credential_pair", "deletion_failure_message")
24 changes: 16 additions & 8 deletions backend/danswer/background/celery/celery_app.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import traceback
from datetime import timedelta
from typing import Any
from typing import cast
Expand Down Expand Up @@ -40,6 +41,7 @@
from danswer.configs.constants import PostgresAdvisoryLocks
from danswer.connectors.factory import instantiate_connector
from danswer.connectors.models import InputType
from danswer.db.connector_credential_pair import add_deletion_failure_message
from danswer.db.connector_credential_pair import (
get_connector_credential_pair,
)
Expand Down Expand Up @@ -97,6 +99,7 @@ def cleanup_connector_credential_pair_task(
Needs to potentially update a large number of Postgres and Vespa docs, including deleting them
or updating the ACL"""
engine = get_sqlalchemy_engine()

with Session(engine) as db_session:
# validate that the connector / credential pair is deletable
cc_pair = get_connector_credential_pair(
Expand All @@ -109,14 +112,13 @@ def cleanup_connector_credential_pair_task(
f"Cannot run deletion attempt - connector_credential_pair with Connector ID: "
f"{connector_id} and Credential ID: {credential_id} does not exist."
)

deletion_attempt_disallowed_reason = check_deletion_attempt_is_allowed(
connector_credential_pair=cc_pair, db_session=db_session
)
if deletion_attempt_disallowed_reason:
raise ValueError(deletion_attempt_disallowed_reason)

try:
deletion_attempt_disallowed_reason = check_deletion_attempt_is_allowed(
connector_credential_pair=cc_pair, db_session=db_session
)
if deletion_attempt_disallowed_reason:
raise ValueError(deletion_attempt_disallowed_reason)

# The bulk of the work is in here, updates Postgres and Vespa
curr_ind_name, sec_ind_name = get_both_index_names(db_session)
document_index = get_default_document_index(
Expand All @@ -127,10 +129,15 @@ def cleanup_connector_credential_pair_task(
document_index=document_index,
cc_pair=cc_pair,
)

except Exception as e:
stack_trace = traceback.format_exc()
error_message = f"Error: {str(e)}\n\nStack Trace:\n{stack_trace}"
add_deletion_failure_message(db_session, cc_pair.id, error_message)
task_logger.exception(
f"Failed to run connector_deletion. "
f"connector_id={connector_id} credential_id={credential_id}"
f"connector_id={connector_id} credential_id={credential_id}\n"
f"Stack Trace:\n{stack_trace}"
)
raise e

Expand Down Expand Up @@ -410,6 +417,7 @@ def check_for_cc_pair_deletion_task() -> None:
task_logger.info(
f"Deleting the {cc_pair.name} connector credential pair"
)

cleanup_connector_credential_pair_task.apply_async(
kwargs=dict(
connector_id=cc_pair.connector.id,
Expand Down
12 changes: 12 additions & 0 deletions backend/danswer/db/connector_credential_pair.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,18 @@ def get_connector_credential_pairs(
return list(results.all())


def add_deletion_failure_message(
db_session: Session,
cc_pair_id: int,
failure_message: str,
) -> None:
cc_pair = get_connector_credential_pair_from_id(cc_pair_id, db_session)
if not cc_pair:
return
cc_pair.deletion_failure_message = failure_message
db_session.commit()


def get_cc_pair_groups_for_ids(
db_session: Session,
cc_pair_ids: list[int],
Expand Down
3 changes: 3 additions & 0 deletions backend/danswer/db/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,9 @@ class ConnectorCredentialPair(Base):
connector_id: Mapped[int] = mapped_column(
ForeignKey("connector.id"), primary_key=True
)

deletion_failure_message: Mapped[str | None] = mapped_column(String, nullable=True)

credential_id: Mapped[int] = mapped_column(
ForeignKey("credential.id"), primary_key=True
)
Expand Down
2 changes: 2 additions & 0 deletions backend/danswer/server/documents/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ class CCPairFullInfo(BaseModel):
latest_deletion_attempt: DeletionAttemptSnapshot | None
is_public: bool
is_editable_for_current_user: bool
deletion_failure_message: str | None

@classmethod
def from_models(
Expand Down Expand Up @@ -262,6 +263,7 @@ def from_models(
latest_deletion_attempt=latest_deletion_attempt,
is_public=cc_pair_model.is_public,
is_editable_for_current_user=is_editable_for_current_user,
deletion_failure_message=cc_pair_model.deletion_failure_message,
)


Expand Down
25 changes: 25 additions & 0 deletions web/src/app/admin/connector/[ccPairId]/DeletionErrorStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { FiInfo } from "react-icons/fi";

export default function DeletionErrorStatus({
deletion_failure_message,
}: {
deletion_failure_message: string;
}) {
return (
<div className="mt-2 rounded-md border border-error-300 bg-error-50 p-4 text-error-600 max-w-3xl">
<div className="flex items-center">
<h3 className="text-base font-medium">Deletion Error</h3>
<div className="ml-2 relative group">
<FiInfo className="h-4 w-4 text-error-600 cursor-help" />
<div className="absolute z-10 w-64 p-2 mt-2 text-sm bg-white rounded-md shadow-lg opacity-0 group-hover:opacity-100 transition-opacity duration-300 border border-gray-200">
This error occurred while attempting to delete the connector. You
may re-attempt a deletion by clicking the &quot;Delete&quot; button.
</div>
</div>
</div>
<div className="mt-2 text-sm">
<p>{deletion_failure_message}</p>
</div>
</div>
);
}
12 changes: 12 additions & 0 deletions web/src/app/admin/connector/[ccPairId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { useEffect, useRef, useState } from "react";
import { CheckmarkIcon, EditIcon, XIcon } from "@/components/icons/icons";
import { usePopup } from "@/components/admin/connectors/Popup";
import { updateConnectorCredentialPairName } from "@/lib/connector";
import DeletionErrorStatus from "./DeletionErrorStatus";

// since the uploaded files are cleaned up after some period of time
// re-indexing will not work for the file connector. Also, it would not
Expand Down Expand Up @@ -184,6 +185,17 @@ function Main({ ccPairId }: { ccPairId: number }) {
: "This connector belongs to groups where you don't have curator permissions, so it's not editable."}
</div>
)}

{ccPair.deletion_failure_message &&
ccPair.status === ConnectorCredentialPairStatus.DELETING && (
<>
<div className="mt-6" />
<DeletionErrorStatus
deletion_failure_message={ccPair.deletion_failure_message}
/>
</>
)}

{credentialTemplates[ccPair.connector.source] &&
ccPair.is_editable_for_current_user && (
<>
Expand Down
1 change: 1 addition & 0 deletions web/src/app/admin/connector/[ccPairId]/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface CCPairFullInfo {
latest_deletion_attempt: DeletionAttemptSnapshot | null;
is_public: boolean;
is_editable_for_current_user: boolean;
deletion_failure_message: string | null;
}

export interface PaginatedIndexAttempts {
Expand Down
12 changes: 12 additions & 0 deletions web/tailwind-themes/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,18 @@ module.exports = {

input: "#ffffff",

// Error colors
"error-50": "#fef2f2",
"error-100": "#fee2e2",
"error-200": "#fecaca",
"error-300": "#fca5a5",
"error-400": "#f87171",
"error-500": "#ef4444",
"error-600": "#dc2626",
"error-700": "#b91c1c",
"error-800": "#991b1b",
"error-900": "#7f1d1d",

background: "#fafafa", // 50
"background-100": "#f5f5f5", // neutral-100
"background-125": "#F1F2F4", // gray-125
Expand Down

0 comments on commit 58bdf9d

Please sign in to comment.