Skip to content
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

Take up double the memory when encode File. #3036

Open
iWECon opened this issue Jul 10, 2023 · 3 comments
Open

Take up double the memory when encode File. #3036

iWECon opened this issue Jul 10, 2023 · 3 comments
Labels
bug Something isn't working

Comments

@iWECon
Copy link

iWECon commented Jul 10, 2023

Describe the bug

It seems to take up double the memory when use try clientRequest.content.encode(Encodable.self, as: .formData).

In addition,
when the request fails, the memory will not be released normally (still taking up double the memory).
After the request is successful, the memory will be released normally.

import Vapor

struct SendFile {
    private static func generateVideoFile(_ filePath: String) throws -> File {
        let videoFileURL = URL(fileURLWithPath: filePath)
        var videoData = try Data(contentsOf: videoFileURL)
        return File(data: ByteBuffer(data: videoData), filename: (filePath as NSString).lastPathComponent)
    }
    
    struct SendFile: Codable {
        let file: File
        let userID: String
    }

    static func sendVideo(_ filePath: String, to userID: String, app: Application) async throws {
        let file = try generateVideoFile(filePath)
        
        let sendFile = SendFile(file: file, userID: userID)
        
        let response = try await app.client.post("URI") { clientRequest in
            try clientRequest.content.encode(sendFile, as: .formData)
        }
        // ...
    }
}

Environment

  • Vapor 4
  • Ubuntu 20.04
@iWECon iWECon added the bug Something isn't working label Jul 10, 2023
@MahdiBM
Copy link
Contributor

MahdiBM commented Jul 10, 2023

Have you tried to test the memory footage in release mode too, or just in debug mode?
The form-data encoder has a known issue of taking up too much resources in debug builds, unlike in release builds where it performs just like it should.

@iWECon
Copy link
Author

iWECon commented Jul 10, 2023

Have you tried to test the memory footage in release mode too, or just in debug mode?
The form-data encoder has a known issue of taking up too much resources in debug builds, unlike in release builds where it performs just like it should.

😂 I found this problem in the release mode.

@iWECon
Copy link
Author

iWECon commented Jul 10, 2023

I found a temporary solution:

public struct VideoPayload: Codable, Content {
    var video: File? // << important use Optional<File>
    var thumbnail: File?  // << important use Optional<File>
    public init(video: File, thumbnail: File) {
        self.video = video
        self.thumbnail = thumbnail
    }
    
    mutating public func clear() {
        video = nil
        thumbnail = nil
    }
}

var payload = VideoPayload(
    video: File(
        data: ByteBuffer(data: try Data(contentsOf: URL(fileURLWithPath: video.videoPath))),
        filename: (video.videoPath as NSString).lastPathComponent
    ),
    thumbnail: File(
        data: ByteBuffer(data: try Data(contentsOf: URL(fileURLWithPath: thumbPath))),
        filename: (thumbPath as NSString).lastPathComponent
    )
)

let response = try await app.client.post(uri) { cr in
    // &payload, without copy data
    try cr.content.encode(&payload, as: .formData)
    
    // clear data in memory << ⚠️ see here, clear File after encoded
    payload.clear()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants