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

feat(iter): Added context accepting variants of Map & ForEach #114

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

rkoehl05
Copy link

@rkoehl05 rkoehl05 commented May 15, 2023

Added context handling to the functions in the iter package to support cancelling execution if any of the tasks fail or if the context itself is cancelled externally. As part of this change, I also re-implemented the ForEach* functions to use ContextPool from the pool package.

iter/map.go Outdated Show resolved Hide resolved
@rkoehl05 rkoehl05 marked this pull request as ready for review May 22, 2023 19:55
iter/map.go Outdated Show resolved Hide resolved
@camdencheek
Copy link
Member

Hi @rkoehl05! Thanks for the PR and sorry for the slow response. Taking a look this morning

iter/iter.go Outdated
Comment on lines 117 to 121
runner := pool.New().
WithContext(octx).
WithCancelOnError().
WithFirstError().
WithMaxGoroutines(iter.MaxGoroutines)
Copy link
Member

Choose a reason for hiding this comment

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

I would prefer to not add a dependency on pool in the iter package. Because the iter package knows the number of inputs and the number of outputs in advance, it can be considerably more efficient than the pool package, which must work for an unbounded number of iterations.

I think it would be good to reconcile this PR with the patterns in #104. In particular, the FailFast flag should mean similar things iterating with ForEachErr and ForEachCtx.

Copy link
Author

Choose a reason for hiding this comment

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

The abstractions built into ContextPool offered a simple way to achieve the functionality I was looking for with regard to context cancellation without having to duplicate code. Both iter and pool used waitgroup underneath. I'm not too sure what efficiency gains are made by having two separate implementations but I'd be happy to switch it back to original setup.

Additionally, as a further argument for using ContextPool, the FailFast behavior seems like it could be easily implemented by using the new bool to optionally call WithFirstError() on the underlying pool. Right now I call that by default assuming the caller is only interested in the first error when using a context.

I could add the *Err variants as extensions to what I have here that just return an error but don't require a context.

Copy link
Member

Choose a reason for hiding this comment

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

the FailFast behavior seems like it could be easily implemented by using the new bool to optionally call WithFirstError() on the underlying pool

Related: #118

The abstractions built into ContextPool offered a simple way to achieve the functionality I was looking for with regard to context cancellation without having to duplicate code

You might be right. The simplicity of using a Pool to back the iter package is likely more valuable than the minor efficiency gains we get from knowing the size of the set in advance (which basically boil down to allocating in advance and not needing a mutex).

Let me noodle on the design a bit and get back to ya. I'll probably open a draft that unifies this with #104 and the pool package in general, maybe just replacing the Iterator structs with configured pools.

iter/iter.go Outdated Show resolved Hide resolved
// MapCtx is the same as Map except it also accepts a context
// that it uses to manages the execution of tasks.
// The context is cancelled on task failure and the first error is returned.
func (m Mapper[T, R]) MapCtx(ctx context.Context, input []T, f func(context.Context, *T) (R, error)) ([]R, error) {

Choose a reason for hiding this comment

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

I'm interested in this as well 🙂 What do you think about using a builder for the Mapper? I would like a WithCancelOnError as well.

@adrianlungu
Copy link

Would be nice to get this merged! 🙏

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.

5 participants