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

start argument for produce. #845

Open
jcornaz opened this issue Nov 20, 2018 · 3 comments
Open

start argument for produce. #845

jcornaz opened this issue Nov 20, 2018 · 3 comments

Comments

@jcornaz
Copy link
Contributor

jcornaz commented Nov 20, 2018

Since the onCompletion argument of produce is marked with InternalCoroutinesApi, the reason why it was introduced (#279) is back on the table.

In short: if a resource is open before produce, there is no (easy) way to make sure that the resource will always be closed.

The simplest solution, is probably to specify start = CoroutineStart.ATOMIC.

But for that we need a start argument to produce.

@jcornaz
Copy link
Contributor Author

jcornaz commented Feb 24, 2019

Any update?

What should we do in the mean time? Is the best to use onCompletion despite the fact is it marked with InternalCoroutinesApi?

If yes could you mark it with ObsoleteCoroutinesApi instead?

@elizarov
Copy link
Contributor

I'm working on a replacement DSL API for that. I have not yet created a separate issue for it (I'll have it soon). The approach I'm currently prototyping is this. You replace produce with produceBuilder (and it works for all other coroutine builders in the same way) and add catch/finally sections to it:

produceBuilder(...) { /* as before *}
    .finally { /* will be always invoked before completion */ }
    .build()

Here finally block is going to be executed before completion and in the same context as the coroutine (as opposed to the random thread that onCompletion used) and if this block fails, then the corresponding exception is going to become completion result of the job, similarly to how try { ... } finally { ... } works.

@zach-klippenstein
Copy link
Contributor

I have a different use case for this. I have a coroutine that runs a loop to process a UI framework (calculate an initial state, wait for events, calculate new state, repeat). It starts this coroutine using the produce builder to publish updates on a channel. The coroutine is guaranteed to calculate its first state without suspending. In order to integrate with legacy, non-coroutine code, I need to get that first state from a non-suspend function.

As far as I know, there are two ways to do this:

  1. Call poll() on the channel. Assumes the initial value has already been sent.
  2. Call runBlocking { channel.receive() }.

I would prefer 1, because it doesn't actually block at all, and doesn't require the overhead of allocating a whole new dispatch queue and coroutine just to receive a value that should be immediately available anyway. However, the legacy code that needs to get this value is running on the same thread and hasn't given the produce coroutine a chance to execute its initial continuation yet.

I believe if I could start the produce coroutine with CoroutineStart.UNDISPATCHED, that initial value would get calculated and sent on the channel immediately, and I could use poll.

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

No branches or pull requests

3 participants