From 2b81b6673f6a7e4fdf96ff8dc02d856decc28f82 Mon Sep 17 00:00:00 2001 From: AichiB7A Date: Tue, 27 May 2025 21:17:45 +0800 Subject: [PATCH 1/6] [Observability] Add type check and try-except in otel (#20319) --- api/extensions/ext_otel.py | 69 ++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/api/extensions/ext_otel.py b/api/extensions/ext_otel.py index 538a88a4fa..6dcfa7bec6 100644 --- a/api/extensions/ext_otel.py +++ b/api/extensions/ext_otel.py @@ -22,16 +22,20 @@ def on_user_loaded(_sender, user: Union["Account", "EndUser"]): from opentelemetry.trace import get_current_span if user: - current_span = get_current_span() - if isinstance(user, Account) and user.current_tenant_id: - tenant_id = user.current_tenant_id - elif isinstance(user, EndUser): - tenant_id = user.tenant_id - else: - return - if current_span: - current_span.set_attribute("service.tenant.id", tenant_id) - current_span.set_attribute("service.user.id", user.id) + try: + current_span = get_current_span() + if isinstance(user, Account) and user.current_tenant_id: + tenant_id = user.current_tenant_id + elif isinstance(user, EndUser): + tenant_id = user.tenant_id + else: + return + if current_span: + current_span.set_attribute("service.tenant.id", tenant_id) + current_span.set_attribute("service.user.id", user.id) + except Exception: + logging.exception("Error setting tenant and user attributes") + pass def init_app(app: DifyApp): @@ -54,21 +58,25 @@ def init_app(app: DifyApp): def response_hook(span: Span, status: str, response_headers: list): if span and span.is_recording(): - if status.startswith("2"): - span.set_status(StatusCode.OK) - else: - span.set_status(StatusCode.ERROR, status) - - status = status.split(" ")[0] - status_code = int(status) - status_class = f"{status_code // 100}xx" - attributes: dict[str, str | int] = {"status_code": status_code, "status_class": status_class} - request = flask.request - if request and request.url_rule: - attributes[SpanAttributes.HTTP_TARGET] = str(request.url_rule.rule) - if request and request.method: - attributes[SpanAttributes.HTTP_METHOD] = str(request.method) - _http_response_counter.add(1, attributes) + try: + if status.startswith("2"): + span.set_status(StatusCode.OK) + else: + span.set_status(StatusCode.ERROR, status) + + status = status.split(" ")[0] + status_code = int(status) + status_class = f"{status_code // 100}xx" + attributes: dict[str, str | int] = {"status_code": status_code, "status_class": status_class} + request = flask.request + if request and request.url_rule: + attributes[SpanAttributes.HTTP_TARGET] = str(request.url_rule.rule) + if request and request.method: + attributes[SpanAttributes.HTTP_METHOD] = str(request.method) + _http_response_counter.add(1, attributes) + except Exception: + logging.exception("Error setting status and attributes") + pass instrumentor = FlaskInstrumentor() if dify_config.DEBUG: @@ -99,7 +107,7 @@ def init_app(app: DifyApp): class ExceptionLoggingHandler(logging.Handler): """Custom logging handler that creates spans for logging.exception() calls""" - def emit(self, record): + def emit(self, record: logging.LogRecord): try: if record.exc_info: tracer = get_tracer_provider().get_tracer("dify.exception.logging") @@ -114,9 +122,12 @@ def init_app(app: DifyApp): }, ) as span: span.set_status(StatusCode.ERROR) - span.record_exception(record.exc_info[1]) - span.set_attribute("exception.type", record.exc_info[0].__name__) - span.set_attribute("exception.message", str(record.exc_info[1])) + if record.exc_info[1]: + span.record_exception(record.exc_info[1]) + span.set_attribute("exception.message", str(record.exc_info[1])) + if record.exc_info[0]: + span.set_attribute("exception.type", record.exc_info[0].__name__) + except Exception: pass From f233a64eb56213a7c74960284b424928d857d38a Mon Sep 17 00:00:00 2001 From: -LAN- Date: Tue, 27 May 2025 22:41:07 +0800 Subject: [PATCH 2/6] fix(workflow): fetch user failed when workflow run in parallel mode (#20321) Signed-off-by: -LAN- --- api/core/app/apps/advanced_chat/app_generator.py | 2 +- api/core/app/apps/agent_chat/app_generator.py | 2 +- api/core/app/apps/workflow/app_generator.py | 2 +- api/core/workflow/graph_engine/graph_engine.py | 15 ++++++++++++++- .../workflow/nodes/iteration/iteration_node.py | 16 +++++++++++++++- 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/api/core/app/apps/advanced_chat/app_generator.py b/api/core/app/apps/advanced_chat/app_generator.py index 50a843c7e8..fdd1a776f8 100644 --- a/api/core/app/apps/advanced_chat/app_generator.py +++ b/api/core/app/apps/advanced_chat/app_generator.py @@ -452,7 +452,7 @@ class AdvancedChatAppGenerator(MessageBasedAppGenerator): for var, val in context.items(): var.set(val) - # Save current user before entering new app context + # FIXME(-LAN-): Save current user before entering new app context from flask import g saved_user = None diff --git a/api/core/app/apps/agent_chat/app_generator.py b/api/core/app/apps/agent_chat/app_generator.py index d5ee324360..158196f24d 100644 --- a/api/core/app/apps/agent_chat/app_generator.py +++ b/api/core/app/apps/agent_chat/app_generator.py @@ -232,7 +232,7 @@ class AgentChatAppGenerator(MessageBasedAppGenerator): for var, val in context.items(): var.set(val) - # Save current user before entering new app context + # FIXME(-LAN-): Save current user before entering new app context from flask import g saved_user = None diff --git a/api/core/app/apps/workflow/app_generator.py b/api/core/app/apps/workflow/app_generator.py index 5442927413..6ea90e5a3d 100644 --- a/api/core/app/apps/workflow/app_generator.py +++ b/api/core/app/apps/workflow/app_generator.py @@ -411,7 +411,7 @@ class WorkflowAppGenerator(BaseAppGenerator): for var, val in context.items(): var.set(val) - # Save current user before entering new app context + # FIXME(-LAN-): Save current user before entering new app context from flask import g saved_user = None diff --git a/api/core/workflow/graph_engine/graph_engine.py b/api/core/workflow/graph_engine/graph_engine.py index 36273d8ec1..f61965e07e 100644 --- a/api/core/workflow/graph_engine/graph_engine.py +++ b/api/core/workflow/graph_engine/graph_engine.py @@ -9,7 +9,7 @@ from copy import copy, deepcopy from datetime import UTC, datetime from typing import Any, Optional, cast -from flask import Flask, current_app +from flask import Flask, current_app, has_request_context from configs import dify_config from core.app.apps.base_app_queue_manager import GenerateTaskStoppedError @@ -540,8 +540,21 @@ class GraphEngine: for var, val in context.items(): var.set(val) + # FIXME(-LAN-): Save current user before entering new app context + from flask import g + + saved_user = None + if has_request_context() and hasattr(g, "_login_user"): + saved_user = g._login_user + with flask_app.app_context(): try: + # Restore user in new app context + if saved_user is not None: + from flask import g + + g._login_user = saved_user + q.put( ParallelBranchRunStartedEvent( parallel_id=parallel_id, diff --git a/api/core/workflow/nodes/iteration/iteration_node.py b/api/core/workflow/nodes/iteration/iteration_node.py index a061dfc354..ea0b6863c9 100644 --- a/api/core/workflow/nodes/iteration/iteration_node.py +++ b/api/core/workflow/nodes/iteration/iteration_node.py @@ -7,7 +7,7 @@ from datetime import UTC, datetime from queue import Empty, Queue from typing import TYPE_CHECKING, Any, Optional, cast -from flask import Flask, current_app +from flask import Flask, current_app, has_request_context from configs import dify_config from core.variables import ArrayVariable, IntegerVariable, NoneVariable @@ -586,7 +586,21 @@ class IterationNode(BaseNode[IterationNodeData]): """ for var, val in context.items(): var.set(val) + + # FIXME(-LAN-): Save current user before entering new app context + from flask import g + + saved_user = None + if has_request_context() and hasattr(g, "_login_user"): + saved_user = g._login_user + with flask_app.app_context(): + # Restore user in new app context + if saved_user is not None: + from flask import g + + g._login_user = saved_user + parallel_mode_run_id = uuid.uuid4().hex graph_engine_copy = graph_engine.create_copy() variable_pool_copy = graph_engine_copy.graph_runtime_state.variable_pool From eaaf55149735891678301eb3bd261c047ba054d1 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Wed, 28 May 2025 16:36:08 +0800 Subject: [PATCH 3/6] fix: Instance is not bound to a Session (#20347) Signed-off-by: -LAN- --- .../app/task_pipeline/easy_ui_based_generate_task_pipeline.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py b/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py index a98a42f5df..6c768fd86c 100644 --- a/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py +++ b/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py @@ -455,8 +455,6 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline, MessageCycleMan agent_thought: Optional[MessageAgentThought] = ( db.session.query(MessageAgentThought).filter(MessageAgentThought.id == event.agent_thought_id).first() ) - db.session.refresh(agent_thought) - db.session.close() if agent_thought: return AgentThoughtStreamResponse( From 42505010583fa8936b0a091aa4e019159682c225 Mon Sep 17 00:00:00 2001 From: "Junjie.M" <118170653@qq.com> Date: Wed, 28 May 2025 16:36:32 +0800 Subject: [PATCH 4/6] fix: reset password page dark style (#20350) --- web/app/reset-password/set-password/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/reset-password/set-password/page.tsx b/web/app/reset-password/set-password/page.tsx index dd1c4ef1f4..ee4c114a77 100644 --- a/web/app/reset-password/set-password/page.tsx +++ b/web/app/reset-password/set-password/page.tsx @@ -105,7 +105,7 @@ const ChangePasswordForm = () => {
-
+
{/* Password */}