Skip to content

Conversation

@shaohuzhang1
Copy link
Contributor

fix: Return the link to the connection pool after the node execution is completed

@f2c-ci-robot
Copy link

f2c-ci-robot bot commented Aug 28, 2025

Adding the "do-not-merge/release-note-label-needed" label because no release-note block was detected, please follow our release note process to remove it.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@f2c-ci-robot
Copy link

f2c-ci-robot bot commented Aug 28, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

connection.close()

def run_node_async(self, node):
future = executor.submit(self.run_node, node)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

No issues found and no optimizations required for this code. It's structured well, clear, and follows best practices. The connection.close() call after releasing node chunks is appropriate for resource management in Django applications.

connection.close()
if f_lib is None:
raise Exception(_('The function has been deleted'))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The code contains a few recommendations:

  1. Connection Management: It's important to manage database connections properly, especially when dealing with Django applications. Closing the connection at all times can lead to performance issues and resource leaks. Instead of closing it here, you might want to ensure that any other operations involving databases do not leave open unnecessary connections.

  2. Validation Logic: There's redundancy in handling exceptions for the missing tool library. You should only catch this exception once and raise the appropriate error message without duplicating logic within is_valid.

Here's an improved version of the code:

from typing import Type

+import functools

from django.db import connection
from django.db.models import QuerySet
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers


class FunctionLibNodeParamsSerializer(serializers.Serializer):

    def __init__(self, *args, **kwargs):
        kwargs['context'] = {**kwargs.get('context', {}), 'connection': connection}
        super().__init__(*args, **kwargs)

    @functools.lru_cache(maxsize=None)
    def is_valid(self, *, raise_exception=False):
        errors = self._validate_data()

        if errors:
            if not raise_exception:
                return False
            else:
                for field, messages in errors.items():
                    self.add_error(field=field, errors=messages)
                return False
        return True

    def _validate_data(self):        
        super().is_valid(raise_exception=True)
        try:
            query_set = Tool.objects.filter(id=self.validated_data["tool_lib_id"])
            if not query_set.exists():  # Check existence before fetching first item
                raise Exception(_("The function has been deleted"))
            f_lib = query_set.first()          
        except KeyError as e:
            errors = {'tool_lib_id': [_("Invalid tool lib ID"), str(e)]}     
            return errors

Key Improvements:

  • Context Handling: The serializer now passes the database connection context into the serializer via its initialization method.
  • Exception Handling: Only one occurrence of checking for a null f_lib is made using exception handling.
  • Redundancy Elimination: Removed redundant logic for catching key errors during data validation.

These changes help optimize the serializer's logic while ensuring proper database management, which is crucial for maintaining application performance.

@shaohuzhang1 shaohuzhang1 merged commit d53b4dc into v2 Aug 28, 2025
3 of 5 checks passed
@shaohuzhang1 shaohuzhang1 deleted the pr@v2@feat_connection branch August 28, 2025 08:08
connection.close()
get_authorized_model = DatabaseModelManage.get_model("get_authorized_model")
if model and model.workspace_id != workspace_id and get_authorized_model is not None:
model = get_authorized_model(QuerySet(Model).filter(id=_id), workspace_id).first()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is an issue with this code that needs to be addressed:

The function get_model_by_id does not manage database connections correctly. Specifically, it attempts to close the connection after filtering a queryset but before returning the model result. This can lead to data inconsistencies because the query may have started on one connection and the subsequent filter operation might happen on another.

To fix this, you should ensure that the same database connection is used throughout the entire process of querying and filtering. Here's how you can modify the function:

from django.db import connection

def get_model_by_id(_id, workspace_id):
    try:
        with connection.cursor() as cursor:
            # Assuming Model and DatabaseModelManage are models from Django
            query = f"SELECT * FROM {Model._meta.db_table} WHERE id=%s AND workspace_id=%s"
            cursor.execute(query, (_id, workspace_id))
            
            model_data = cursor.fetchone()
            if model_data:
                model = Model.objects.create(**model_data)
                
                if model and model.workspace_id != workspace_id:
                    authorized_model_query = "SELECT * FROM auth_authorized_models WHERE model_id = %s AND workspace_id = %s;"
                    authorized_cursor = connection.cursor()
                    authorized_cursor.execute(authorized_model_query, (model.id, workspace_id,))
                    
                    authorized_model_data = authorized_cursor.fetchone()
                    if authorized_model_data:
                        authorized_model = DatabaseModelManage.queryset_class().create(**authorized_model_data)
                        
                        return authorized_model
                        
                return model
                
    except Exception as e:
        print(f"An error occurred: {e}")
        return None
    
    finally:
        # Always use commit=False when using .fetchone() without creating a new object
        connection.commit()

Key Changes:

  1. Use of Context Manager: Encapsulate database operations within a context manager (with connection.cursor()), which automatically manages opening and closing the connection.
  2. Database Operations: Perform all necessary database interactions through the same connection to avoid cross-correlation issues.
  3. Commit Operation: Ensure that connection.commit() is called after fetching data to ensure changes are saved.
  4. Safe Data Handling: Use parameterized queries (%s) instead of string interpolation for security purposes.

By making these adjustments, the code will handle database connections properly and mitigate potential data consistency issues related to different connection contexts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants