Skip to content

chore: add redis for getting built plugin #20118

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

LeeeeeeM
Copy link
Contributor

@LeeeeeeM LeeeeeeM commented May 22, 2025

Summary

It will cost long time getting all built plugins

Screenshots

in dev mode

Before After
image image

Checklist

Important

Please review the checklist below before submitting your pull request.

  • 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 dev/reformat(backend) and cd web && npx lint-staged(frontend) to appease the lint gods

@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label May 22, 2025
@LeeeeeeM
Copy link
Contributor Author

@crazywoola CC

@LeeeeeeM LeeeeeeM force-pushed the chore/add-redis-plugin branch 2 times, most recently from 6c1f6af to 81fc4b2 Compare May 22, 2025 10:09
@Dustyposa
Copy link

Looks like miss the logic when the new BuiltinToolProvider been add into the db then need clear the redis cache.
eg: in file: builtin_tools_manage_service.py

@LeeeeeeM LeeeeeeM force-pushed the chore/add-redis-plugin branch from 81fc4b2 to 813d156 Compare May 23, 2025 08:21
@LeeeeeeM
Copy link
Contributor Author

Looks like miss the logic when the new BuiltinToolProvider been add into the db then need clear the redis cache. eg: in file: builtin_tools_manage_service.py

done

@crazywoola crazywoola requested review from Yeuoly and Copilot and removed request for Yeuoly May 26, 2025 08:36
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Contributor

@bowenliang123 bowenliang123 left a comment

Choose a reason for hiding this comment

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

LGTM overall. Good to have this improvement.
Suggested PR title: introducing caching for builtin plugin list

"""
Generate the Redis key for caching.
"""
return BuiltinToolManageService.REDIS_KEY_PREFIX.format(user_id=user_id, tenant_id=tenant_id)
Copy link
Contributor

Choose a reason for hiding this comment

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

REDIS_KEY_PREFIX is never used again, which could be removed from BuiltinToolManageService. And simply use the string format style to generate cache key instead.

REDIS_TTL = 60 * 10 # Cache expires in 10 minutes

@staticmethod
def get_redis_key(user_id: str, tenant_id: str) -> str:
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
def get_redis_key(user_id: str, tenant_id: str) -> str:
def generate_cache_key(user_id: str, tenant_id: str) -> str:

prefer the netual concept cache instead of specific implementation redis.

Comment on lines +180 to +181
redis_key = BuiltinToolManageService.get_redis_key(user_id, tenant_id)
redis_client.delete(redis_key)
Copy link
Contributor

Choose a reason for hiding this comment

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

Better to squash in a single code line for clearer readibility.

Comment on lines +217 to +218
redis_key = BuiltinToolManageService.get_redis_key(user_id, tenant_id)
redis_client.delete(redis_key)
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto.

from models.tools import BuiltinToolProvider
from services.tools.tools_transform_service import ToolTransformService

logger = logging.getLogger(__name__)


class BuiltinToolManageService:
REDIS_KEY_PREFIX = "builtin_tools:user:{user_id}:tenant:{tenant_id}"
REDIS_TTL = 60 * 10 # Cache expires in 10 minutes
Copy link
Contributor

Choose a reason for hiding this comment

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

Make this configurable in dify_config. And prevent a general config name for this.

decrypt_credentials=True,
)
# Deserialize cached data directly into a list of dictionaries
deserialized_data = json.loads(cached_data)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Recommend to use ToolProviderApiEntity.model_validate_json() to reach a better performance.

Copy link
Collaborator

@Yeuoly Yeuoly May 29, 2025

Choose a reason for hiding this comment

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

TypeAdapter(Sequence[ToolProviderApiEntity]) may simplify it.

# Deserialize cached data directly into a list of dictionaries
deserialized_data = json.loads(cached_data)
return [ToolProviderApiEntity(**item) for item in deserialized_data]
except (json.JSONDecodeError, TypeError) as e:
Copy link
Collaborator

Choose a reason for hiding this comment

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

json.JSONDecodeError can be replaced to pydantic.ValidationError if model_validate_json was used.


return BuiltinToolProviderSort.sort(result)
# Serialize and store in Redis
serialized_result = json.dumps([jsonable_encoder(item) for item in result])
Copy link
Collaborator

Choose a reason for hiding this comment

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

pydantic.TypeAdapter(list[Any]).dump_json(result) is a better choice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size:L This PR changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants