Future cancellation

classic Classic list List threaded Threaded
47 messages Options
123
Reply | Threaded
Open this post in threaded view
|

Future cancellation

Ron Buckton-2

I’ve created separate gists for three different ways that I am currently investigating as a means to support the cancellation of a Future. These can be found here:

 

1.       Cancellation using Future: https://gist.github.com/rbuckton/5486149

2.       Cancellation using Future.cancelable: https://gist.github.com/rbuckton/5484591

3.       Cancellation using Future#cancel: https://gist.github.com/rbuckton/5484478

 

Each has a list of some of the benefits and issues I’ve seen while experimenting with each approach, as well as possible changes to the various APIs or algorithms for Future to make each happen.

 

In general, cancellation of a Future can be beneficial in a number of cases.  One example is the case where you are requesting a resource from a remote server using XHR. If the request was being made to fetch a page of data, and the user opted to move to the next page before the current page completed loading, it no longer becomes necessary to continue fetching the remote resource. In addition, it is no longer necessary to handle any additional computation or transformation logic that would have resulted from the successful completion of the fetch operation. Having the ability to cancel the request allows an application to quickly release resources that it no longer needs.

 

It is also useful to be able to handle the cancelation of a long running task that might be executing in a Worker. In this case, cleanup logic that is part of cancelation would request the worker to close, ending the current operation and releasing resources.

 

Both of the above examples are indicative of cancelling the root of an operation, but there are also circumstances where you might want to cancel a chained Future and any Future chained from it, without canceling the root. In the previous example regarding paged data, I might wish to allow the fetch operation to complete so that I could cache the data for quick retrieval, but would only want to cancel any possible UI updates that might occur in a chained Future.

 

I’m interested to hear what others think with respect to properly handling cancellation with Futures.

 

Ron


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Future cancellation

Lucas Smith-2
<base href="x-msg://3308/">IMO, cancelation is not appropriate for promises/futures. (sticking with the name "promises", sorry for the distraction).

Promises represent a value, but have no knowledge of the work involved to get the value. The work knows about the promise, the promise doesn't know about the work. If you want to externalize additional controls to allow your code to steer the work involved in getting the promised value, that is justification for a separate class that contains a promise, likely exposing a 'then()' method linked to its internal promise. The code used to set up the resolve/reject conditions can externalize the reject method to enable cancelation for instances of that class. But the promise remains limited to a value proxy. The more a class needs to know about the work, the more specialized the class becomes, which Promise has avoided pretty well so far.

Luke

On Apr 29, 2013, at 6:57 PM, Ron Buckton <[hidden email]> wrote:

I’ve created separate gists for three different ways that I am currently investigating as a means to support the cancellation of a Future. These can be found here:
 
1.       Cancellation using Future: https://gist.github.com/rbuckton/5486149
2.       Cancellation using Future.cancelable: https://gist.github.com/rbuckton/5484591
3.       Cancellation using Future#cancel: https://gist.github.com/rbuckton/5484478
 
Each has a list of some of the benefits and issues I’ve seen while experimenting with each approach, as well as possible changes to the various APIs or algorithms for Future to make each happen.
 
In general, cancellation of a Future can be beneficial in a number of cases.  One example is the case where you are requesting a resource from a remote server using XHR. If the request was being made to fetch a page of data, and the user opted to move to the next page before the current page completed loading, it no longer becomes necessary to continue fetching the remote resource. In addition, it is no longer necessary to handle any additional computation or transformation logic that would have resulted from the successful completion of the fetch operation. Having the ability to cancel the request allows an application to quickly release resources that it no longer needs.
 
It is also useful to be able to handle the cancelation of a long running task that might be executing in a Worker. In this case, cleanup logic that is part of cancelation would request the worker to close, ending the current operation and releasing resources.
 
Both of the above examples are indicative of cancelling the root of an operation, but there are also circumstances where you might want to cancel a chained Future and any Future chained from it, without canceling the root. In the previous example regarding paged data, I might wish to allow the fetch operation to complete so that I could cache the data for quick retrieval, but would only want to cancel any possible UI updates that might occur in a chained Future.
 
I’m interested to hear what others think with respect to properly handling cancellation with Futures.
 
Ron
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Future cancellation

Alex Russell-4
In reply to this post by Ron Buckton-2
These are horribly confused -- and likely foot-gun -- designs. 

First, synchronous resolution needs some justification. I don't understand why you've added it in the first design. The question of "does the Resolver know it is resolved?" is entirely independent of the visibility of that resolution to the outside world. I don't think this flag even makes sense.

In terms of blessing one or another static method for generating the cancellable tuple (as you do in your first two designs), why does it have to be in the design at this point? The current design in DOM provides a small contract to keep us from fighting over how to distinguish cancellation from other error values (the side-contract everyone would need to re-create at great expense), but purposefully avoids doing this for the sake of simplicitly. I don't get why you're trying to expand this contract in the core spec. Just subclass. Should it become so common, we can revisit this later.

Lastly, your final design is irretrievably broken in a way the first two aren't: it vends to anyone who has a handle to the Future the capability to reject it.

The DOM design has studiously avoided this class of fatal design errors so far. It's the key reason why Resolvers and Futures are separate objects. No such design will fly in this group.

Regards

On Tuesday, April 30, 2013, Ron Buckton wrote:

I’ve created separate gists for three different ways that I am currently investigating as a means to support the cancellation of a Future. These can be found here:

 

1.       Cancellation using Future: https://gist.github.com/rbuckton/5486149

2.       Cancellation using Future.cancelable: https://gist.github.com/rbuckton/5484591

3.       Cancellation using Future#cancel: https://gist.github.com/rbuckton/5484478

 

Each has a list of some of the benefits and issues I’ve seen while experimenting with each approach, as well as possible changes to the various APIs or algorithms for Future to make each happen.

 

In general, cancellation of a Future can be beneficial in a number of cases.  One example is the case where you are requesting a resource from a remote server using XHR. If the request was being made to fetch a page of data, and the user opted to move to the next page before the current page completed loading, it no longer becomes necessary to continue fetching the remote resource. In addition, it is no longer necessary to handle any additional computation or transformation logic that would have resulted from the successful completion of the fetch operation. Having the ability to cancel the request allows an application to quickly release resources that it no longer needs.

 

It is also useful to be able to handle the cancelation of a long running task that might be executing in a Worker. In this case, cleanup logic that is part of cancelation would request the worker to close, ending the current operation and releasing resources.

 

Both of the above examples are indicative of cancelling the root of an operation, but there are also circumstances where you might want to cancel a chained Future and any Future chained from it, without canceling the root. In the previous example regarding paged data, I might wish to allow the fetch operation to complete so that I could cache the data for quick retrieval, but would only want to cancel any possible UI updates that might occur in a chained Future.

 

I’m interested to hear what others think with respect to properly handling cancellation with Futures.

 

Ron


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Future cancellation

Brendan Eich-3
In reply to this post by Lucas Smith-2
Lucas Smith wrote:
> IMO, cancelation is not appropriate for promises/futures. (sticking
> with the name "promises", sorry for the distraction).

Agreed.

/be
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Future cancellation

Juan Ignacio Dopazo
In reply to this post by Alex Russell-4
2013/4/30 Alex Russell <[hidden email]>
First, synchronous resolution needs some justification. I don't understand why you've added it in the first design.

When I first read about the synchronous resolution flag I thought it made sense, for example in the context of network requests. When a network request is completed you can call resolve() with the synchronous flag because you know you're in a new tick of the event loop. It basically allows you to avoid scheduling notification in the future when you already know you're being asynchronous.

Juan

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Future cancellation

Sam L'ecuyer
In reply to this post by Brendan Eich-3
> Lucas Smith wrote:
>> IMO, cancelation is not appropriate for promises/futures. (sticking
>> with the name "promises", sorry for the distraction).

> Agreed.

Perhaps I'm missing something, but is cancel() conceptually different from passing a Future's corresponding Resolver around so that the program can invoke reject() at will?  This seems like it's a new, "irretrievably broken" way to do something you already can do.

-sam



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Future cancellation

Kevin Gadd
Even if a consequence of cancellation is rejection (I'm not sure this is necessarily true), cancellation is different in that rejection comes from the source of the value, which is why it's on the resolver, while cancellation goes in the other direction - the recipient(s) of a value are telling the source that it is not needed, and the source is free to respond in any way it chooses.

I should note that in my particular case, I did not map cancellation in my API to rejection; it's a separate state with separate callbacks and pipelines in part to avoid the problem of having confusion between whether a future was rejected or cancelled. I don't think it makes much sense for cancellation to reject a future since that would cause your existing rejection callback to get invoked with a cancellation error, when the odds are that *you* initiated the cancellation in the first place.

I don't know what the right shape for a cancellation API is,  but one should not assume that this problem is inherent to cancellation. I don't think it is. Cancellation may be hopelessly flawed as a feature in an ocap model where unprivileged consumers are sharing a single Future instance, though, because in that case I don't know how you would track the 'cancellation' state of a future across multiple unprivileged consumers, and it would probably expose a communication sidechannel just like weak references do.

-kg


On Tue, Apr 30, 2013 at 11:01 AM, Sam L'ecuyer <[hidden email]> wrote:
> Lucas Smith wrote:
>> IMO, cancelation is not appropriate for promises/futures. (sticking
>> with the name "promises", sorry for the distraction).

> Agreed.

Perhaps I'm missing something, but is cancel() conceptually different from passing a Future's corresponding Resolver around so that the program can invoke reject() at will?  This seems like it's a new, "irretrievably broken" way to do something you already can do.

-sam



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Future cancellation

Ron Buckton-2
In reply to this post by Alex Russell-4

Alex,

 

Thank you for the feedback.  I’ve also added two more gists:

 

4. Cancellation using CancellationTokenSource: https://gist.github.com/rbuckton/5490373

5. Cancellation using CancelableFuture subclass: https://gist.github.com/rbuckton/5490482

 

Each one of these is an attempt to find out exactly what does and doesn’t work with various mechanisms for cancellation that have been discussed on these lists as well as in various libraries.

 

In [1] I added the synchronous flag as a way to ensure that the Future that is used for cancellation can resolve and have its resolve callbacks run in time. It’s not exactly necessary but there are some cases where not being able to cancel synchronously could bite a developer:

 

function someAsync(cancelFuture) {

  return new Future(function (resolver) {

    var handle = setImmediate(function () { … });

    cancelFuture.done(function () { clearImmediate(handle); });

  });

}

 

var { token, cancel } = createCanceler();

var f = someAsync(token);

cancel();

 

Due to asynchronous resolution, even though cancel() is called synchronously it will be scheduled *after* the setImmediate call.

 

[2] was based on a side discussion around cancellation and similarities to revocable Proxies.

 

[3] was based on providing a simple means of cancellation, but I agree that there is a danger that a Future that is referenced by multiple consumers could be canceled by any consumer.

 

[4] is inspired by cooperative cancellation of Tasks in .NET. I’ve used this quite often and found it to be a powerful cancellation mechanism. It has the advantage of being very explicit about where responsibilities lie as part of cancellation and reducing pollution of the Future API, but it does add additional complexity around setup. I’m personally in favor of this approach, though not so fond of the name of types.  [1] is partially based on this approach as well, except that CTS cancels synchronously and can automatically reject a Future.

 

[5] is a possible approach (albeit a naïve implementation) of cancellation via a subclass. In its current incarnation it suffers from the same issues a [1] and [2], but can be mitigated by having it directly call the resolver’s resolve algorithm with the synchronous flag set. It also gets lost when using Future.any, etc.

 

My intent currently is not to advocate any of these approaches. Rather; I’m trying to catalogue each approach as I’ve come across them specifically to gather this kind of feedback. 

 

Best regards,

Ron

 
Sent from Windows Mail
 
From: Alex Russell
Sent: ‎Tuesday‎, ‎April‎ ‎30‎, ‎2013 ‎2‎:‎54‎ ‎AM
To: Ron Buckton
Cc: es-discuss, [hidden email], Tab Atkins Jr.
 
These are horribly confused -- and likely foot-gun -- designs. 

First, synchronous resolution needs some justification. I don't understand why you've added it in the first design. The question of "does the Resolver know it is resolved?" is entirely independent of the visibility of that resolution to the outside world. I don't think this flag even makes sense.

In terms of blessing one or another static method for generating the cancellable tuple (as you do in your first two designs), why does it have to be in the design at this point? The current design in DOM provides a small contract to keep us from fighting over how to distinguish cancellation from other error values (the side-contract everyone would need to re-create at great expense), but purposefully avoids doing this for the sake of simplicitly. I don't get why you're trying to expand this contract in the core spec. Just subclass. Should it become so common, we can revisit this later.

Lastly, your final design is irretrievably broken in a way the first two aren't: it vends to anyone who has a handle to the Future the capability to reject it.

The DOM design has studiously avoided this class of fatal design errors so far. It's the key reason why Resolvers and Futures are separate objects. No such design will fly in this group.

Regards

On Tuesday, April 30, 2013, Ron Buckton wrote:

I’ve created separate gists for three different ways that I am currently investigating as a means to support the cancellation of a Future. These can be found here:

 

1.       Cancellation using Future: https://gist.github.com/rbuckton/5486149

2.       Cancellation using Future.cancelable: https://gist.github.com/rbuckton/5484591

3.       Cancellation using Future#cancel: https://gist.github.com/rbuckton/5484478

 

Each has a list of some of the benefits and issues I’ve seen while experimenting with each approach, as well as possible changes to the various APIs or algorithms for Future to make each happen.

 

In general, cancellation of a Future can be beneficial in a number of cases.  One example is the case where you are requesting a resource from a remote server using XHR. If the request was being made to fetch a page of data, and the user opted to move to the next page before the current page completed loading, it no longer becomes necessary to continue fetching the remote resource. In addition, it is no longer necessary to handle any additional computation or transformation logic that would have resulted from the successful completion of the fetch operation. Having the ability to cancel the request allows an application to quickly release resources that it no longer needs.

 

It is also useful to be able to handle the cancelation of a long running task that might be executing in a Worker. In this case, cleanup logic that is part of cancelation would request the worker to close, ending the current operation and releasing resources.

 

Both of the above examples are indicative of cancelling the root of an operation, but there are also circumstances where you might want to cancel a chained Future and any Future chained from it, without canceling the root. In the previous example regarding paged data, I might wish to allow the fetch operation to complete so that I could cache the data for quick retrieval, but would only want to cancel any possible UI updates that might occur in a chained Future.

 

I’m interested to hear what others think with respect to properly handling cancellation with Futures.

 

Ron


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Future cancellation

Sam L'ecuyer
In reply to this post by Kevin Gadd

> I don't know what the right shape for a cancellation API is,  but one
> should not assume that this problem is inherent to cancellation. I don't
> think it is.

Take my input with a grain of salt, but I think it is.

Futures form a cascading pipeline (a series of tubes, if you will) that it promises to follow, either succeeding or failing but always continuing.  Cancellation doesn't fit that model, because it involves either destructively reshaping the pipeline after it's started or trying to shove events in the wrong direction.  If a value is no longer needed and you know ahead of time that it may not be, then a) keep the resolver and reject (reject() takes a value.  Use it.), or b) put an `if` in the success callback.  

-sam




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Future cancellation

Kevin Smith
In reply to this post by Brendan Eich-3



On Tue, Apr 30, 2013 at 10:26 AM, Brendan Eich <[hidden email]> wrote:
Lucas Smith wrote:
IMO, cancelation is not appropriate for promises/futures. (sticking with the name "promises", sorry for the distraction).

Agreed.


Agree as well.   More conceptually, we must not conflate *operations* with *results*.  "Cancel" is an action that applies to operations, not results.

{ Kevin }

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Future cancellation

Kevin Gadd
Strongly agreed; however future cancellation should not be inferred to mean that a task is cancelled. Rather, it means that the value the future represents is no longer needed, which may implicitly result in the cancellation of an actual operation.

To provide a simple example (from an actual application):
I have some stack traces from a running application, and I want to map the individual offsets in those traces to resolved symbols. This is an expensive operation, so I do it asynchronously.
So, I have a function that maps a given offset to a resolved symbol, with a signature like Future<Symbol> getSymbolForOffset (uint offset). This function returns a future that will be completed when the symbol is available.
Now, each one of these calls does not necessarily map to a single symbol resolution operation - symbol resolution is expensive, so I may batch requests up into larger groups to reduce round-trips and improve performance.
Given this, I have a many-to-one mapping - many futures mapping to a single operation. Simply exposing the ability to cancel that operation doesn't make any sense; the underlying operation is an implementation detail. And, as you mentioned, cancelling one of those futures should not cancel the operation; the ability to cancel that operation directly should not be exposed to an owner of just one of those futures.
Regardless, by being able to 'dispose' or mark as unneeded the individual futures, you can ensure that if all the futures an operation is about to fulfill are not needed, the operation can automatically be cancelled.

I see it as difficult to satisfy these scenarios without some sort of approach to future disposal/cancellation, and I see this as separate from questions of how one goes about cancelling tasks, even if task cancellation is sometimes driven by future disposal/cancellation.

-kg


On Tue, Apr 30, 2013 at 12:23 PM, Kevin Smith <[hidden email]> wrote:



On Tue, Apr 30, 2013 at 10:26 AM, Brendan Eich <[hidden email]> wrote:
Lucas Smith wrote:
IMO, cancelation is not appropriate for promises/futures. (sticking with the name "promises", sorry for the distraction).

Agreed.


Agree as well.   More conceptually, we must not conflate *operations* with *results*.  "Cancel" is an action that applies to operations, not results.

{ Kevin }

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Future cancellation

Jonas Sicking-2
In reply to this post by Ron Buckton-2
On Mon, Apr 29, 2013 at 6:57 PM, Ron Buckton <[hidden email]> wrote:

> I’ve created separate gists for three different ways that I am currently
> investigating as a means to support the cancellation of a Future. These can
> be found here:
>
>
>
> 1.       Cancellation using Future: https://gist.github.com/rbuckton/5486149
>
> 2.       Cancellation using Future.cancelable:
> https://gist.github.com/rbuckton/5484591
>
> 3.       Cancellation using Future#cancel:
> https://gist.github.com/rbuckton/5484478
>
>
>
> Each has a list of some of the benefits and issues I’ve seen while
> experimenting with each approach, as well as possible changes to the various
> APIs or algorithms for Future to make each happen.
>
>
>
> In general, cancellation of a Future can be beneficial in a number of cases.
> One example is the case where you are requesting a resource from a remote
> server using XHR. If the request was being made to fetch a page of data, and
> the user opted to move to the next page before the current page completed
> loading, it no longer becomes necessary to continue fetching the remote
> resource. In addition, it is no longer necessary to handle any additional
> computation or transformation logic that would have resulted from the
> successful completion of the fetch operation. Having the ability to cancel
> the request allows an application to quickly release resources that it no
> longer needs.
>
>
>
> It is also useful to be able to handle the cancelation of a long running
> task that might be executing in a Worker. In this case, cleanup logic that
> is part of cancelation would request the worker to close, ending the current
> operation and releasing resources.
>
>
>
> Both of the above examples are indicative of cancelling the root of an
> operation, but there are also circumstances where you might want to cancel a
> chained Future and any Future chained from it, without canceling the root.
> In the previous example regarding paged data, I might wish to allow the
> fetch operation to complete so that I could cache the data for quick
> retrieval, but would only want to cancel any possible UI updates that might
> occur in a chained Future.
>
>
>
> I’m interested to hear what others think with respect to properly handling
> cancellation with Futures.

I do not think that we should add cancellation on the base Future
interface. I.e. we shouldn't make *all* Futures cancellable.

Cancelability should only be possible when the implementation of the
Future would actually stop doing work if the Future is cancelled. I.e.
cancelling a Future shouldn't simply prevent the result callbacks from
being called, but it should prevent whatever work is needed to
calculate the result from happening.

However it would be very complex and expensive if we had to make all
APIs that want to use Futures also support being cancelled.

The solution is to create a subclass of Future which allows the
back-end work to be cancelled. I.e. a CancelableFuture, or
AbortableFuture. This subclass would have a .cancel() or .abort()
method on it. The FutureResolver created when the CancelableFuture is
created would have a callback which is called when .cancel()/.abort()
is called.

This would be useful if we create an Future-based API for doing
network requests or file reading.

In other words, the should be the choice of the implementor of a given
API to determine if it wants to return a Future which can be
cancelled, or one that can't. Obviously this needs to be documented
for that API, just like you document that the API returns a Future at
all.

/ Jonas
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: Future cancellation

Ron Buckton-2
Jonas,

As I mentioned to Alex Russel, I'm also interested in the benefits of using a subclass. I have two additional gists around cancellation, one that uses an external token for cancelation [1] (similar to .NET/C#), and another that uses a subclass [2] (though I still need to spend some additional time on the subclass sample).

[1] https://gist.github.com/rbuckton/5490373
[2] https://gist.github.com/rbuckton/5490482

I agree with the sentiment that Future#cancel is a bad idea.

Ron

> -----Original Message-----
> From: Jonas Sicking [mailto:[hidden email]]
> Sent: Tuesday, April 30, 2013 4:47 PM
> To: Ron Buckton
> Cc: es-discuss; [hidden email]; Tab Atkins Jr.
> Subject: Re: Future cancellation
>
> On Mon, Apr 29, 2013 at 6:57 PM, Ron Buckton <[hidden email]>
> wrote:
> > I've created separate gists for three different ways that I am
> > currently investigating as a means to support the cancellation of a
> > Future. These can be found here:
> >
> >
> >
> > 1.       Cancellation using Future: https://gist.github.com/rbuckton/5486149
> >
> > 2.       Cancellation using Future.cancelable:
> > https://gist.github.com/rbuckton/5484591
> >
> > 3.       Cancellation using Future#cancel:
> > https://gist.github.com/rbuckton/5484478
> >
> >
> >
> > Each has a list of some of the benefits and issues I've seen while
> > experimenting with each approach, as well as possible changes to the
> > various APIs or algorithms for Future to make each happen.
> >
> >
> >
> > In general, cancellation of a Future can be beneficial in a number of cases.
> > One example is the case where you are requesting a resource from a
> > remote server using XHR. If the request was being made to fetch a page
> > of data, and the user opted to move to the next page before the
> > current page completed loading, it no longer becomes necessary to
> > continue fetching the remote resource. In addition, it is no longer
> > necessary to handle any additional computation or transformation logic
> > that would have resulted from the successful completion of the fetch
> > operation. Having the ability to cancel the request allows an
> > application to quickly release resources that it no longer needs.
> >
> >
> >
> > It is also useful to be able to handle the cancelation of a long
> > running task that might be executing in a Worker. In this case,
> > cleanup logic that is part of cancelation would request the worker to
> > close, ending the current operation and releasing resources.
> >
> >
> >
> > Both of the above examples are indicative of cancelling the root of an
> > operation, but there are also circumstances where you might want to
> > cancel a chained Future and any Future chained from it, without canceling
> the root.
> > In the previous example regarding paged data, I might wish to allow
> > the fetch operation to complete so that I could cache the data for
> > quick retrieval, but would only want to cancel any possible UI updates
> > that might occur in a chained Future.
> >
> >
> >
> > I'm interested to hear what others think with respect to properly
> > handling cancellation with Futures.
>
> I do not think that we should add cancellation on the base Future interface. I.e.
> we shouldn't make *all* Futures cancellable.
>
> Cancelability should only be possible when the implementation of the Future
> would actually stop doing work if the Future is cancelled. I.e.
> cancelling a Future shouldn't simply prevent the result callbacks from being
> called, but it should prevent whatever work is needed to calculate the result
> from happening.
>
> However it would be very complex and expensive if we had to make all APIs
> that want to use Futures also support being cancelled.
>
> The solution is to create a subclass of Future which allows the back-end work to
> be cancelled. I.e. a CancelableFuture, or AbortableFuture. This subclass would
> have a .cancel() or .abort() method on it. The FutureResolver created when the
> CancelableFuture is created would have a callback which is called when
> .cancel()/.abort() is called.
>
> This would be useful if we create an Future-based API for doing network
> requests or file reading.
>
> In other words, the should be the choice of the implementor of a given API to
> determine if it wants to return a Future which can be cancelled, or one that
> can't. Obviously this needs to be documented for that API, just like you
> document that the API returns a Future at all.
>
> / Jonas


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Future cancellation

Bjoern Hoehrmann
In reply to this post by Jonas Sicking-2
* Jonas Sicking wrote:

>I do not think that we should add cancellation on the base Future
>interface. I.e. we shouldn't make *all* Futures cancellable.
>
>Cancelability should only be possible when the implementation of the
>Future would actually stop doing work if the Future is cancelled. I.e.
>cancelling a Future shouldn't simply prevent the result callbacks from
>being called, but it should prevent whatever work is needed to
>calculate the result from happening.
>
>However it would be very complex and expensive if we had to make all
>APIs that want to use Futures also support being cancelled.

You seem to be arguing based on the word "cancel". The semantic would
rather be "Please note that I am no longer interested in this value",
which would make sense even if the "work" is not actually "stopped",
and, accordingly, it would not be complex and expensive to support.

In other words, I think most people would agree that a "forced stop"
option for everything is complex and expensive and should not be re-
quired, but that does not necessarily invalidate the ideas that moti-
vate a "cancel" option.

>The solution is to create a subclass of Future which allows the
>back-end work to be cancelled. I.e. a CancelableFuture, or
>AbortableFuture. This subclass would have a .cancel() or .abort()
>method on it. The FutureResolver created when the CancelableFuture is
>created would have a callback which is called when .cancel()/.abort()
>is called.

"Future" "subclasses" seem rather dubious to me.
--
Björn Höhrmann · mailto:[hidden email] · http://bjoern.hoehrmann.de
Am Badedeich 7 · Telefon: +49(0)160/4415681 · http://www.bjoernsworld.de
25899 Dagebüll · PGP Pub. KeyID: 0xA4357E78 · http://www.websitedev.de/ 
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Future cancellation

Jonas Sicking-2
In reply to this post by Ron Buckton-2
I think the subclass is the way to go.

However there are some tricky issues that need to be resolved:

What happens if the Future is cancelled after it has been resolved? To
stick with the Future API, once you've started delivering results, you
shouldn't change what result is delivered.

What happens if cancel() is called multiple times?

Then there's of course the issue of what we should do with APIs that
combine several Futures into a single one. Like Future.every() etc.

Similarly, there's also the issue of what to do with chaining.

I'm tempted to say that if you create combined or dependent Futures,
you still only have the ability to cancel them through the original
CancelableFuture.

Like others have pointed out here, we need to keep "operations"
separate from "delivering results". Combined and dependent Futures are
combining the delivering of results, but they don't combine the
operations.

/ Jonas

On Tue, Apr 30, 2013 at 5:42 PM, Ron Buckton <[hidden email]> wrote:

> Jonas,
>
> As I mentioned to Alex Russel, I'm also interested in the benefits of using a subclass. I have two additional gists around cancellation, one that uses an external token for cancelation [1] (similar to .NET/C#), and another that uses a subclass [2] (though I still need to spend some additional time on the subclass sample).
>
> [1] https://gist.github.com/rbuckton/5490373
> [2] https://gist.github.com/rbuckton/5490482
>
> I agree with the sentiment that Future#cancel is a bad idea.
>
> Ron
>
>> -----Original Message-----
>> From: Jonas Sicking [mailto:[hidden email]]
>> Sent: Tuesday, April 30, 2013 4:47 PM
>> To: Ron Buckton
>> Cc: es-discuss; [hidden email]; Tab Atkins Jr.
>> Subject: Re: Future cancellation
>>
>> On Mon, Apr 29, 2013 at 6:57 PM, Ron Buckton <[hidden email]>
>> wrote:
>> > I've created separate gists for three different ways that I am
>> > currently investigating as a means to support the cancellation of a
>> > Future. These can be found here:
>> >
>> >
>> >
>> > 1.       Cancellation using Future: https://gist.github.com/rbuckton/5486149
>> >
>> > 2.       Cancellation using Future.cancelable:
>> > https://gist.github.com/rbuckton/5484591
>> >
>> > 3.       Cancellation using Future#cancel:
>> > https://gist.github.com/rbuckton/5484478
>> >
>> >
>> >
>> > Each has a list of some of the benefits and issues I've seen while
>> > experimenting with each approach, as well as possible changes to the
>> > various APIs or algorithms for Future to make each happen.
>> >
>> >
>> >
>> > In general, cancellation of a Future can be beneficial in a number of cases.
>> > One example is the case where you are requesting a resource from a
>> > remote server using XHR. If the request was being made to fetch a page
>> > of data, and the user opted to move to the next page before the
>> > current page completed loading, it no longer becomes necessary to
>> > continue fetching the remote resource. In addition, it is no longer
>> > necessary to handle any additional computation or transformation logic
>> > that would have resulted from the successful completion of the fetch
>> > operation. Having the ability to cancel the request allows an
>> > application to quickly release resources that it no longer needs.
>> >
>> >
>> >
>> > It is also useful to be able to handle the cancelation of a long
>> > running task that might be executing in a Worker. In this case,
>> > cleanup logic that is part of cancelation would request the worker to
>> > close, ending the current operation and releasing resources.
>> >
>> >
>> >
>> > Both of the above examples are indicative of cancelling the root of an
>> > operation, but there are also circumstances where you might want to
>> > cancel a chained Future and any Future chained from it, without canceling
>> the root.
>> > In the previous example regarding paged data, I might wish to allow
>> > the fetch operation to complete so that I could cache the data for
>> > quick retrieval, but would only want to cancel any possible UI updates
>> > that might occur in a chained Future.
>> >
>> >
>> >
>> > I'm interested to hear what others think with respect to properly
>> > handling cancellation with Futures.
>>
>> I do not think that we should add cancellation on the base Future interface. I.e.
>> we shouldn't make *all* Futures cancellable.
>>
>> Cancelability should only be possible when the implementation of the Future
>> would actually stop doing work if the Future is cancelled. I.e.
>> cancelling a Future shouldn't simply prevent the result callbacks from being
>> called, but it should prevent whatever work is needed to calculate the result
>> from happening.
>>
>> However it would be very complex and expensive if we had to make all APIs
>> that want to use Futures also support being cancelled.
>>
>> The solution is to create a subclass of Future which allows the back-end work to
>> be cancelled. I.e. a CancelableFuture, or AbortableFuture. This subclass would
>> have a .cancel() or .abort() method on it. The FutureResolver created when the
>> CancelableFuture is created would have a callback which is called when
>> .cancel()/.abort() is called.
>>
>> This would be useful if we create an Future-based API for doing network
>> requests or file reading.
>>
>> In other words, the should be the choice of the implementor of a given API to
>> determine if it wants to return a Future which can be cancelled, or one that
>> can't. Obviously this needs to be documented for that API, just like you
>> document that the API returns a Future at all.
>>
>> / Jonas
>
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Future cancellation

Jonas Sicking-2
In reply to this post by Bjoern Hoehrmann
On Tue, Apr 30, 2013 at 5:56 PM, Bjoern Hoehrmann <[hidden email]> wrote:

> * Jonas Sicking wrote:
>>I do not think that we should add cancellation on the base Future
>>interface. I.e. we shouldn't make *all* Futures cancellable.
>>
>>Cancelability should only be possible when the implementation of the
>>Future would actually stop doing work if the Future is cancelled. I.e.
>>cancelling a Future shouldn't simply prevent the result callbacks from
>>being called, but it should prevent whatever work is needed to
>>calculate the result from happening.
>>
>>However it would be very complex and expensive if we had to make all
>>APIs that want to use Futures also support being cancelled.
>
> You seem to be arguing based on the word "cancel". The semantic would
> rather be "Please note that I am no longer interested in this value",
> which would make sense even if the "work" is not actually "stopped",
> and, accordingly, it would not be complex and expensive to support.
>
> In other words, I think most people would agree that a "forced stop"
> option for everything is complex and expensive and should not be re-
> quired, but that does not necessarily invalidate the ideas that moti-
> vate a "cancel" option.

"I am no longer interested in receiving this value" is definitely a
separation operation than "I want the operation to be stopped".

If you're no longer interested in receiving a particular value, that
may or may not mean that others are interested in that value. Futures
support multiple callers registering to be told about a particular
result. And, as importantly, they support people registering to
receive a result at any point in time.

If we want to support the semantics of "I am no longer interested in
receiving this value" then I propose that we add a way to "unregister"
an individual .then() callback. But I'm not at all sure that this is a
use case that is important enough to implement. Callers can always
ignore the value once it comes in.

/ Jonas
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Future cancellation

Jonas Sicking-2
In reply to this post by Jonas Sicking-2
On Tue, Apr 30, 2013 at 7:37 PM, Jonas Sicking <[hidden email]> wrote:

> Then there's of course the issue of what we should do with APIs that
> combine several Futures into a single one. Like Future.every() etc.
>
> Similarly, there's also the issue of what to do with chaining.
>
> I'm tempted to say that if you create combined or dependent Futures,
> you still only have the ability to cancel them through the original
> CancelableFuture.
>
> Like others have pointed out here, we need to keep "operations"
> separate from "delivering results". Combined and dependent Futures are
> combining the delivering of results, but they don't combine the
> operations.

There are actually some very big similarities here with
ProgressFuture. There too we are facing the question of what to do if
multiple Futures, some of which are ProgressFutures, are combined
using Future.every, or what to do if a Future is chained after a
ProgressFuture.

It isn't actually surprising that the same issues arise.
ProgressFuture basically delivers progress about an "operation" rather
than a "result".

My gut instinct is still the same. Combining results using dependent
or combined Futures is great. However trying to combine operations
seems like a lot of complexity and easily a source of confusion.

/ Jonas
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: Future cancellation

Domenic Denicola-2
From: [hidden email] [mailto:[hidden email]] On Behalf Of Jonas Sicking

> It isn't actually surprising that the same issues arise. ProgressFuture basically delivers progress about an "operation" rather than a "result".

I agree. I think both progress and cancellation (of underlying operations) are attractive nuisances. They seem like they fit in well with the model, and would be useful for certain use cases. But they are actually very different, and not tied to the underling promise semantics at all—which are of a first class value representing a promised "result," as you put it, not representing an ongoing "operation."

I lean toward not specifying or including them at all. Although you can try to stuff them naively into the promise semantics, you end up needing to complicate the conceptual model in order to make them behave as you wish. As you point out, this is clearly visible with the various combinators. But it's also visible in basic semantic questions that arise: e.g. downward progress propagation/transformation, or the role of throwing inside a progress handler, or upward cancellation progagation/reaction, or downward cancellation forking, or the role of rejections in cancellation. You soon realize that you're trying to smush in semantics where they don't belong.

In other words, separate abstractions for cancellation or progress, unrelated to promises, seem best.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Future cancellation

Kevin Gadd
To be honest, I haven't yet seen an explanation of why 'I no longer have any need for the contents of this future' is not tied to the underlying semantics of a future. Where else would it go? I agree with you that complicating a primitive in order to support a small subset of use cases is undesirable, and it does seem like perhaps end-user subclassing of futures/promises addresses all these use cases. But it is troubling to me to consistently see real use cases dismissed as somehow unworthy of consideration because they do not meet some unspecified semantic bar.

And to restate some points that have cropped up in the thread multiple times so far, since they are relevant to your arguments:

Future cancellation is not the same as task cancellation; it is different. I would agree with any suggestion that using the names 'cancel' or 'abort' probably leads people to assume that they are the same. I prefer the term 'disposal' but that is perhaps overly .NETty and implies things that do not apply to JS.

Layering disposal onto a promise from the outside is fine, but requires that all consumers of an API have prior knowledge of the way the API is implemented; that is, the API author has to expose disposal beforehand (even if it is not used) and the consumer has to know that it is needed. This exposes whether or not disposal is *actually used* by an implementation when it should be an implementation detail. Much like how - to pick an arbitrary example - finally blocks in a generator should run if you enumerate the generator with for-of, it is desirable to have a universal way to indicate that a future's value is unneeded by a single consumer such that any given API implementer can extend their implementation seamlessly to abort operations that are no longer needed. This allows significant changes to the backend of an operation (caching, batching, etc) without changing the public API. (Note that you can probably address this with a Future subclass instead of baking disposal into Future itself, or by exposing some sort of public function that you can call on a future to indicate that you are done with it and making that function a no-op for non-disposable futures. I don't have a strong opinion).

I'm fine with cancellation and progress being nuked from futures for conceptual purity; simpler is probably better. But if you're going to kill them, you should do it based on sound reasoning, otherwise they're just going to keep cropping up again and again because people want them and will probably not accept a justification that seems based on a misunderstanding of their arguments.

Given the choice between explicitly not specifying disposal, and specifying an 'encouraged way to do it' (i.e. via subclassing), I would also lean towards the latter. That is, if you're going to say 'we don't need to spec disposal', by demonstrating an incredibly easy way to do it via subclassing, you address any arguments that it must be built into the language or into DOM futures, and you demonstrate a pattern that is expected to work based on the current spec.


-kg


On Tue, Apr 30, 2013 at 9:25 PM, Domenic Denicola <[hidden email]> wrote:
From: [hidden email] [mailto:[hidden email]] On Behalf Of Jonas Sicking

> It isn't actually surprising that the same issues arise. ProgressFuture basically delivers progress about an "operation" rather than a "result".

I agree. I think both progress and cancellation (of underlying operations) are attractive nuisances. They seem like they fit in well with the model, and would be useful for certain use cases. But they are actually very different, and not tied to the underling promise semantics at all—which are of a first class value representing a promised "result," as you put it, not representing an ongoing "operation."

I lean toward not specifying or including them at all. Although you can try to stuff them naively into the promise semantics, you end up needing to complicate the conceptual model in order to make them behave as you wish. As you point out, this is clearly visible with the various combinators. But it's also visible in basic semantic questions that arise: e.g. downward progress propagation/transformation, or the role of throwing inside a progress handler, or upward cancellation progagation/reaction, or downward cancellation forking, or the role of rejections in cancellation. You soon realize that you're trying to smush in semantics where they don't belong.

In other words, separate abstractions for cancellation or progress, unrelated to promises, seem best.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: Future cancellation

Ron Buckton-2
In reply to this post by Domenic Denicola-2
> -----Original Message-----
> From: Domenic Denicola [mailto:[hidden email]]
> Sent: Tuesday, April 30, 2013 9:25 PM
> To: Jonas Sicking; Ron Buckton
> Cc: [hidden email]; es-discuss
> Subject: RE: Future cancellation
>
> From: [hidden email] [mailto:es-discuss-
> [hidden email]] On Behalf Of Jonas Sicking
>
> > It isn't actually surprising that the same issues arise. ProgressFuture
> basically delivers progress about an "operation" rather than a "result".
>
> I agree. I think both progress and cancellation (of underlying operations) are
> attractive nuisances. They seem like they fit in well with the model, and
> would be useful for certain use cases. But they are actually very different,
> and not tied to the underling promise semantics at all—which are of a first
> class value representing a promised "result," as you put it, not representing
> an ongoing "operation."
>
> I lean toward not specifying or including them at all. Although you can try to
> stuff them naively into the promise semantics, you end up needing to
> complicate the conceptual model in order to make them behave as you wish.
> As you point out, this is clearly visible with the various combinators. But it's
> also visible in basic semantic questions that arise: e.g. downward progress
> propagation/transformation, or the role of throwing inside a progress
> handler, or upward cancellation progagation/reaction, or downward
> cancellation forking, or the role of rejections in cancellation. You soon realize
> that you're trying to smush in semantics where they don't belong.
>
> In other words, separate abstractions for cancellation or progress, unrelated
> to promises, seem best.

This is roughly the case with .NET/C# cancellation. In .NET you use an external object to represent cancellation. If a function returns a Future (or "Task" in .NET), it's the function author's decision as to whether they want to accept a cancellation token. This allows the author control over whether they want to support cancellation. It's up to the caller to choose to construct a cancellation token and feed it to the function call. This allows for separation of responsibilities between the Future (which is only responsible for delivering asynchronous completion) and Cancellation (which can provide control over the operation). In .NET though, Tasks do participate in cancellation. They have a unique internal state that represents a cancelled task and a level of control over how to handle chained continuations (via the TaskContinuationOptions enum).

The same can be said for progress notifications in .NET Tasks, as they require a synchronization context to post progress notifications back to the caller who may be in a different thread.  This does illustrate your point though, regarding how Futures, cancellation, and progress are related but distinct.

Ron
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
123