[PR #31131] fix: ensure database is source of truth for plugin trigger sync #33104

Open
opened 2026-02-21 20:52:40 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/langgenius/dify/pull/31131

State: open
Merged: No


  • Remove cache-first decision logic that caused stale cache issues
  • Add stale cache detection and cleanup before creating new records
  • Update cache only after successful database commit (for create/update/delete)
  • Fix distributed lock usage by properly calling acquire() and release()

This fixes the issue where plugin trigger records were not created when Redis cache existed but the corresponding database record was missing.

Important

  1. Make sure you have read our contribution guidelines
  2. Ensure there is an associated issue and you have been assigned to it
  3. Use the correct syntax to link this PR: Fixes #<issue number>.

Summary

Fix Redis cache and database inconsistency issue in plugin trigger sync process.

fix https://github.com/langgenius/dify/issues/31130

Problem:
When syncing plugin trigger relationships, if a stale cache entry exists in Redis but the corresponding database record is missing, the sync process incorrectly skips creating the record. This causes plugin triggers to become non-functional even though they appear in the workflow graph.

Root Cause:

  1. Cache-first decision logic: The code checks Redis cache first and skips nodes found in cache, assuming cache existence implies DB record existence.
  2. Wrong write order: Cache is written before database commit, so if commit fails, the cache becomes stale.
  3. Ineffective distributed lock: Lock object is created but acquire() is never called, allowing race conditions.

Solution:

  1. Use database as the sole decision source - Remove cache-first logic; always check database for record existence.
  2. Clear stale cache entries - Detect and clean stale cache before creating new records, with warning logs.
  3. Update cache only after successful DB commit - For all operations (create/update/delete), update cache only after session.commit() succeeds.
  4. Fix distributed lock usage - Properly call lock.acquire() with timeout and lock.release() in finally block.

File Changed:

  • api/services/trigger/trigger_service.py

Screenshots

Before After
... ...

Checklist

  • This change requires a documentation update, included: Dify Document
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran make lint and make type-check (backend) and cd web && npx lint-staged (frontend) to appease the lint gods
**Original Pull Request:** https://github.com/langgenius/dify/pull/31131 **State:** open **Merged:** No --- - Remove cache-first decision logic that caused stale cache issues - Add stale cache detection and cleanup before creating new records - Update cache only after successful database commit (for create/update/delete) - Fix distributed lock usage by properly calling acquire() and release() This fixes the issue where plugin trigger records were not created when Redis cache existed but the corresponding database record was missing. > [!IMPORTANT] > > 1. Make sure you have read our [contribution guidelines](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md) > 1. Ensure there is an associated issue and you have been assigned to it > 1. Use the correct syntax to link this PR: `Fixes #<issue number>`. ## Summary Fix Redis cache and database inconsistency issue in plugin trigger sync process. fix https://github.com/langgenius/dify/issues/31130 **Problem:** When syncing plugin trigger relationships, if a stale cache entry exists in Redis but the corresponding database record is missing, the sync process incorrectly skips creating the record. This causes plugin triggers to become non-functional even though they appear in the workflow graph. **Root Cause:** 1. Cache-first decision logic: The code checks Redis cache first and skips nodes found in cache, assuming cache existence implies DB record existence. 2. Wrong write order: Cache is written before database commit, so if commit fails, the cache becomes stale. 3. Ineffective distributed lock: Lock object is created but `acquire()` is never called, allowing race conditions. **Solution:** 1. Use database as the sole decision source - Remove cache-first logic; always check database for record existence. 2. Clear stale cache entries - Detect and clean stale cache before creating new records, with warning logs. 3. Update cache only after successful DB commit - For all operations (create/update/delete), update cache only after `session.commit()` succeeds. 4. Fix distributed lock usage - Properly call `lock.acquire()` with timeout and `lock.release()` in finally block. **File Changed:** - `api/services/trigger/trigger_service.py` ## Screenshots | Before | After | |--------|-------| | ... | ... | ## Checklist - [ ] This change requires a documentation update, included: [Dify Document](https://github.com/langgenius/dify-docs) - [x] I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!) - [x] I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change. - [x] I've updated the documentation accordingly. - [x] I ran `make lint` and `make type-check` (backend) and `cd web && npx lint-staged` (frontend) to appease the lint gods
yindo added the pull-request label 2026-02-21 20:52:40 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#33104