Исправлена дедупликация задач синхронизации контакта

This commit is contained in:
mi
2026-08-05 12:59:27 +03:00
parent 1a420eeaf0
commit 5100ba9fc3
3 changed files with 92 additions and 3 deletions
@@ -0,0 +1,75 @@
"""Deduplicate contact mapping and skip no-op identity updates.
Revision ID: 0010_contact_map_dedup
Revises: 0009_chat_message_max
Create Date: 2026-08-05
"""
from collections.abc import Sequence
from alembic import op
revision: str = "0010_contact_map_dedup"
down_revision: str | None = "0009_chat_message_max"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
op.execute(
"""
CREATE OR REPLACE FUNCTION han_app.enqueue_contact_sync()
RETURNS trigger
LANGUAGE plpgsql
SECURITY INVOKER
SET search_path = han_app, pg_temp
AS $$
DECLARE
v_entity_id uuid;
v_task_type text;
v_dedup text;
BEGIN
IF current_setting('han.sync_suppress', true) = 'true' THEN
RETURN NEW;
END IF;
IF TG_TABLE_NAME = 'user_identities' THEN
IF TG_OP = 'UPDATE'
AND NEW.phone_number IS NOT DISTINCT FROM OLD.phone_number
AND NEW.record_status IS NOT DISTINCT FROM OLD.record_status THEN
RETURN NEW;
END IF;
v_entity_id := NEW.id;
v_task_type := CASE WHEN TG_OP = 'INSERT'
THEN 'contact.map_or_create' ELSE 'contact.update' END;
ELSE
v_entity_id := NEW.user_id;
v_task_type := CASE WHEN TG_OP = 'INSERT'
THEN 'contact.map_or_create' ELSE 'contact.update' END;
END IF;
IF v_task_type = 'contact.map_or_create' THEN
-- Identity and profile are inserted during the same bootstrap.
-- A stable key collapses both triggers into one logical task.
v_dedup := v_task_type || ':' || v_entity_id::text;
ELSE
v_dedup := v_task_type || ':' || v_entity_id::text || ':' ||
encode(public.digest(row_to_json(NEW)::text, 'sha256'), 'hex');
END IF;
INSERT INTO han_app.sync_queue
(id, task_type, entity_type, entity_id, dedup_key, payload_json,
status, attempt_count, next_attempt_at, created_at, updated_at)
VALUES
(gen_random_uuid(), v_task_type, 'contact', v_entity_id, v_dedup,
jsonb_build_object('entity_id', v_entity_id), 'pending', 0,
now(), now(), now())
ON CONFLICT (dedup_key) DO NOTHING;
RETURN NEW;
END;
$$
"""
)
def downgrade() -> None:
raise RuntimeError("Contact map-or-create deduplication migration is forward-only")