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 👍

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.

Copy link
Contributor

Choose a reason for hiding this comment

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

We agreed on using defer close(done), but we don't need the select. The pattern would be like this:

done := make(chan struct{})
defer close(done)
channelError := make(chan error, 1)
go func() {
    select {
    case <-ctx.Done():
        channelError <- node.DownloadCancel(cid)
    case <-done:
        // Nothing to do, download finished
    }
}()

_, err = bridge.wait()

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.

Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above re: no select needed.

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.

I'll approve now so that once download and upload are changed, this can be merged quickly 👍

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.

We agreed on using defer close(done), but we don't need the select. The pattern would be like this:

done := make(chan struct{})
defer close(done)
channelError := make(chan error, 1)
go func() {
    select {
    case <-ctx.Done():
        channelError <- node.DownloadCancel(cid)
    case <-done:
        // Nothing to do, download finished
    }
}()

_, err = bridge.wait()

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 as above re: no select needed.

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.

3 participants