Skip to content

fix: Fix the problem that some request connections are not released#8329

Merged
f2c-ci-robot[bot] merged 1 commit intodev-v2from
pr@dev-v2@fix_http_conn
Apr 7, 2025
Merged

fix: Fix the problem that some request connections are not released#8329
f2c-ci-robot[bot] merged 1 commit intodev-v2from
pr@dev-v2@fix_http_conn

Conversation

@ssongliu
Copy link
Copy Markdown
Member

@ssongliu ssongliu commented Apr 7, 2025

No description provided.

@f2c-ci-robot
Copy link
Copy Markdown

f2c-ci-robot Bot commented Apr 7, 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/test-infra repository.

defer client.CloseIdleConnections()
parsedURL, err := url.Parse("http://unix")
if err != nil {
return nil, fmt.Errorf("handle url Parse failed, err: %v \n", err)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The provided code seems to be part of a function that creates an HTTP client for local operations. There are a few areas where improvements can be made:

  1. Resource Cleanup: The defer statement should call client.CloseIdleConnections() to release idle connections.

  2. URL Parsing: The URL is set to "http://unix" regardless of whether the input reqUrl specifies 'local' or not. This might lead to incorrect behavior if used with different types of requests.

  3. Error Handling: Although the current implementation returns errors as formatted strings, this could make debugging more difficult in cases with complex error messages.

Here’s an optimized version of the code:

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"strings"

	dto "github.com/1Panel-dev/1Panel/core/app/dto"
	i18n "github.com/1Panel-dev/1Panel/core/i18n"
)

func NewLocalClient(reqUrl, reqMethod string, body io.Reader) (interface{}, error) {
	client := &http.Client{}

	// Adjust transport based on requirements
	transport := &http.Transport{
		DialContext: (&net.Dialer{}).DialContext,
		TLSHandshakeTimeout: 15 * time.Second,
	}

	switch reqUrl {
	case dto.LocalRequestType:
		host := getUnixSocketHost()
		if host == "" {
			return nil, i18n.GetMessage(i18n.MissingConfigKey)
		}
		transport.Dial = funcctx context.Context, _, _ string) (conn net.Conn, err error) {
			conn, err = net.DialContext(ctx, "unix", host)
			return
		}
	default:
		// Use default TCP connection for other methods
		transport.Dial = (&net.Dialer{}).Dial
	}

	client.Transport = transport

	defer client.CloseIdleConnections()

	request, err := http.NewRequestWithContext(context.Background(), reqMethod, reqUrl, body)
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	responseBody, err := client.Do(request)
	if err != nil {
		return nil, fmt.Errorf("request execution failed: %w", err)
	}
	defer responseBody.Body.Close()

	var result interface{}
	switch responseType {
	case respText:
		bodyContent, err := ioutil.ReadAll(responseBody)
		if err != nil {
			return nil, fmt.Errorf("reading response content failed: %w", err)
		}
		result = string(bodyContent)
	case respJSON:
		err := json.NewDecoder(responseBody).Decode(&result)
		if err != nil && !errors.As(err, new(UnexpectedEOF)) {
			return nil, fmt.Errorf("decoding JSON response failed: %w", err)
		}
	default:
		log.Println(fmt.Sprintf("Unsupported response type: %+v\n\n", responseType))
		return map[string]interface{}{
			"statusCode": int(responseBody.StatusCode),
		}, nil // Return a generic status code map until proper handling implemented.
		panic(errors.New("unreachable")) // Just to satisfy compile-time checks
	}

	return result, nil
}

// Utility functions omitted for brevity

Key Changes:

  1. Switch Statement: Added a switch case for dto.LocalRequestType to handle specific URLs related to Unix sockets.
  2. Default Transport Configuration: Moved the default TCP connection setup outside the switch.
  3. Connection Context: Used a background context when creating the request.
  4. Response Encoding: Decoupled the logic to parse different response types (text vs JSON).

These changes make the code cleaner and more robust, especially considering it's intended for local server interactions.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Apr 7, 2025

defer client.CloseIdleConnections()
response, err := client.Do(req)
if err != nil {
return err
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The code appears to include several areas for improvement, primarily related to resource management and best practices:

  1. Resource Management:

    • The client is created only once at the beginning of the functions and should be retained throughout their execution scope rather than being re-created on each request. This will help manage resources better.
  2. Closing Idle Connections:

    • It's important to close idle connections immediately after use to free up system resources. However, in this case, it seems redundant because both functions close the client using defer client.CloseIdleConnections(). This can be removed as they are already cleaning up properly.
  3. Error Handling:

    • Ensure that the handleDownload function checks if response.Body is not nil before closing it to avoid errors when attempting to read from an unexpected response body closure.
    defer response.Body.Close() // Ensure Body is closed to release resources

Here's a revised version of the code with these improvements:

func (a aliClient) uploadPart(uri string, reader io.Reader) error {
    client := &http.Client{}
    defer func() { _ = client.CloseIdleConnections() }()

    req, err := http.NewRequestWithContext(context.Background(), "PUT", uri, reader)
    if err != nil {
        return err
    }

    resp, err := client.Do(req)
    if err != nil {
        return err
    }
    defer func() { _ = resp.Body.Close() }()
}

func (a aliClient) handleDownload(uri string, target string) error {
    client := &http.Client{Transport: make(http.Transport)} // Use non-default transport for better control over connection pooling
    defer func() { _ = client.CloseIdleConnections() }()
    
    req, err := http.NewRequestWithContext(context.Background(), "GET", uri, nil)
    req.Header.Set("Origin", "https://www.aliyundrive.com")
    req.Header.Set("Referer", "https://www.aliyundrive.com/")

    resp, err := client.Do(req)
    if err != nil {
        return err
    }
    defer func() { _ = resp.Body.Close()}()

    if resp.StatusCode < 200 || resp.StatusCode >= 300 {
        return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
    }

    out, err := os.OpenFile(target, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
    if err != nil {
        return err
    }
    defer func() { _ = out.Close() }()

    _, err = io.Copy(out, resp.Body)
    if err != nil {
        return err
    }

    return nil
}

Key Changes:

  • Reuse Client: The HTTP client (client) is reused across multiple requests within each function to improve efficiency.
  • Connection Pooling: The default HTTP client uses a connection pool, so explicitly setting a custom transport might not be necessary but good practice.
  • Cleanup: Added error handling when closing resp.Body.
  • Status Code Check: Added logic to check for unexpected HTTP status codes in the download function.

defer client.CloseIdleConnections()
response, err := client.Do(req)
if err != nil {
return err
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The defer client.CloseIdleConnections() line is correct and recommended to ensure that idle connections are closed properly after all requests have been processed.

There are no other issues or optimizations in this code snippet.

Copy link
Copy Markdown
Member

@wanghe-fit2cloud wanghe-fit2cloud left a comment

Choose a reason for hiding this comment

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

/lgtm

@wanghe-fit2cloud
Copy link
Copy Markdown
Member

/approve

@f2c-ci-robot
Copy link
Copy Markdown

f2c-ci-robot Bot commented Apr 7, 2025

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: wanghe-fit2cloud

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

The pull request process is described 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

@f2c-ci-robot f2c-ci-robot Bot added the approved label Apr 7, 2025
@f2c-ci-robot f2c-ci-robot Bot merged commit 5cdc316 into dev-v2 Apr 7, 2025
6 checks passed
@f2c-ci-robot f2c-ci-robot Bot deleted the pr@dev-v2@fix_http_conn branch April 7, 2025 07:39
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.

3 participants