Skip to content

Conversation

@2-towns
Copy link
Collaborator

@2-towns 2-towns commented Oct 17, 2025

This PR add context and cancellation for UploadReader, UploadFile and DownloadStream.

@2-towns 2-towns marked this pull request as ready for review October 17, 2025 12:58
@2-towns 2-towns requested a review from emizzle October 17, 2025 12:58
Copy link
Contributor

@emizzle emizzle left a comment

Choose a reason for hiding this comment

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

Nice Arnaud! I definitely like the Context addition 👍

Comment on lines 221 to 226
if err != nil {
if cancelErr != nil {
return fmt.Errorf("upload canceled: %v, but failed to cancel upload session: %v", ctx.Err(), cancelErr)
}
return err
}
Copy link
Contributor

Choose a reason for hiding this comment

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

We should still log something if the session fails to cancel but no error in the download (cancelErr != nil but err == nil). Also, this should be download, not upload.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It is a weird use case where the cancellation will not work so the current download will continue...

I didn't want to add logs inside the Go wrapper in order to let the application consuming it make the choice, but I agree we need to handle this issue.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Should we return an error ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Should we return an error ?

Yes, I think that's a great idea.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we're still missing the condition (cancelErr != nil && err == nil)...?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The function return now cancelErr so if it is not nil (meaning that an error occurred during the cancellation) it will be returned.

cancelErr = node.DownloadCancel(cid)
default:
// continue
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The way I understand this is that the context cancellation is checked only once and is non-blocking due to the default, after download is started. Would it be better to start a go routine and let it cancel the session so that context cancellation can be monitored continuously?

var cancelErr error
go func() {
    <-ctx.Done()
    cancelErr = node.DownloadCancel(cid)
}()
_, err = bridge.wait()
if err != nil { 
  // ...

I have one question though. If we call C.cGoCodexDownloadStream, then the context is cancelled and node.DownloadCancel is called, will the resources consumed in C.cGoCodexDownloadStream be cleaned up properly? I also find the ergonomics of the two calls to be oddly different:

C.cGoCodexDownloadStream
node.DownloadCancel

But both seem to go through the thread boundary back to nim. Or maybe I misunderstood something here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The way I understand this is that the context cancellation is checked only once and is non-blocking due to the default, after download is started. Would it be better to start a go routine and let it cancel the session so that context cancellation can be monitored continuously?

Oh yes you're right, thanks !

will the resources consumed in C.cGoCodexDownloadStream be cleaned up properly?

Yes it will. If there is a cancellation, the stream will be closed, the current call to cGoCodexDownloadStream will generate an error. The bridge.wait() will wait until the error is sent and the resources will be freed thanks to defer bridge.free().

Copy link
Contributor

Choose a reason for hiding this comment

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

Out of curiosity, does this pattern not work?

var cancelErr error
go func() {
    <-ctx.Done()
    cancelErr = node.DownloadCancel(cid)
}()
if cancelErr != nil:
// ...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sorry I didn't reply directly to your pattern, but the problem is that the goroutine will leak because it will wait infinitely for cancellation.

We agreed on discord on using defer close(done) to close the goroutine after the function is done.

Comment on lines 309 to 314
select {
case <-ctx.Done():
cancelErr = node.UploadCancel(sessionId)
default:
// continue
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment as above re: go routine.

}

return bridge.wait()
done := make(chan struct{})
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we also add defer node.UploadCancel on line 300 to keep with the pattern?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The code has changed now, the same pattern as DownloadStream has been applied.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oh sorry I was lost in the different comments / changes. You meant to add the "preventive" defer cancel. Yep will add it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ok done

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants