Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

feat($resource): add support for timeout in cancellable actions #13824

Closed
wants to merge 2 commits into from

Conversation

mrac
Copy link
Contributor

@mrac mrac commented Jan 22, 2016

Old behavior: actions can be either cancellable or have a numeric timeout.
When having both defined, cancellable was ignored.
With this commit: it's possible for actions to have both cancellable:true
and numeric timeout defined.

Example usage:

var Post = $resource('/posts/:id', {id: '@id'}, {
  get: {
    method: 'GET',
    cancellable: true,
    timeout: 10000
  }
});

var currentPost = Post.get({id: 1});
...
// the next request can cancel the previous one
currentPost.$cancelRequest();
currentPost = Post.get({id: 2});

// any of those requests will also timeout, if the response
// doesn't come within 10 seconds

Old behavior: actions can be either cancellable or have a numeric timeout.
When having both defined, cancellable was ignored.
With this commit: it's possible for actions to have both cancellable:true
and numeric timeout defined.

Example usage:

```js
var Post = $resource('/posts/:id', {id: '@id'}, {
  get: {
    method: 'GET',
    cancellable: true,
    timeout: 10000
  }
});

var currentPost = Post.get({id: 1});
...
// the next request can cancel the previous one
currentPost.$cancelRequest();
currentPost = Post.get({id: 2});

// any of those requests will also timeout, if the response
// doesn't come within 10 seconds
```
mrac referenced this pull request Jan 22, 2016
Introduced changes:

- Deprecate passing a promise as `timeout` (for `$resource` actions).
  It never worked correctly anyway.
  Now a warning is logged (using `$log.debug()`) and the property is
  removed.
- Add support for a boolean `cancellable` property in actions'
  configuration, the `$resource` factory's `options` parameter and the
  `$resourceProvider`'s `defaults` property.
  If true, the `$cancelRequest` method (added to all returned values for
  non-instance calls) will abort the request (if it's not already
  completed or aborted).
  If there is a numeric `timeout` specified on the action's configuration,
  the value of `cancellable` will be ignored.

Example usage:

```js
var Post = $resource('/posts/:id', {id: '@id'}, {
  get: {
    method: 'GET',
    cancellable: true
  }
});

var currentPost = Post.get({id: 1});
...
// A moment later the user selects another post, so
// we don't need the previous request any more
currentPost.$cancelRequest();
currentPost = Post.get({id: 2});
...
```

BREAKING CHANGE:

Using a promise as `timeout` is no longer supported and will log a
warning. It never worked the way it was supposed to anyway.

Before:

```js
var deferred = $q.defer();
var User = $resource('/api/user/:id', {id: '@id'}, {
  get: {method: 'GET', timeout: deferred.promise}
});

var user = User.get({id: 1});   // sends a request
deferred.resolve();             // aborts the request

// Now, we need to re-define `User` passing a new promise as `timeout`
// or else all subsequent requests from `someAction` will be aborted
User = $resource(...);
user = User.get({id: 2});
```

After:

```js
var User = $resource('/api/user/:id', {id: '@id'}, {
  get: {method: 'GET', cancellable: true}
});

var user = User.get({id: 1});   // sends a request
instance.$cancelRequest();      // aborts the request

user = User.get({id: 2});
```

Fixes #9332
Closes #13050
Closes #13058
Closes #13210
@gkalpak gkalpak self-assigned this Jan 23, 2016
@gkalpak gkalpak modified the milestones: 1.5.x - migration-facilitation, 1.5.0-rc.2 Jan 23, 2016
} else {
if(cancellable) {
simulatedTimeout = action.timeout;
delete action.timeout;
Copy link
Member

Choose a reason for hiding this comment

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

Why delete it here ? Couldn't we just let it be ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes we don't need to delete it. It gets overwritten anyway later:

httpConfig.timeout = timeoutDeferred.promise;

Copy link
Member

Choose a reason for hiding this comment

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

I don't think it is overwritten. action.timeout is not the same as httpConfig.timeout.
But we shouldn't delete it if we don't have to 😃

@gkalpak
Copy link
Member

gkalpak commented Jan 25, 2016

A couple of minor comments, but LGTM otherwise.

simplify $timeout handler
set `simulatedTimeoutPromise` to null
don't delete action.timeout - not necessary
@gkalpak
Copy link
Member

gkalpak commented Jan 26, 2016

@mrac, thx for working on this ✨ 👍 ✨
I will take it from here (due to tight time constraints to catch the 1.5.0 train).

BTW (so you know for the next time), there were some legitimate failures in tests - nothing major just a couple of whitespace issues that JSCS (rightfully) complaints about 😃
(You can see them on Travis, e.g. here - or you can also run the tests locally with grunt test (to run all the tests) or grunt ci-checks/grunt test:unit/grunt test:e2e etc (to run a specific subset).)

@mrac
Copy link
Contributor Author

mrac commented Jan 26, 2016

@gkalpak great, thanks! Good to hear it's going to be in 1.5.0.
Yeah, I ran unit tests and e2e tests as described here https://docs.angularjs.org/misc/contribute. Apparently grunt test does much more ;) Thanks for the info.

@gkalpak gkalpak closed this in d641901 Jan 26, 2016
@mrac mrac deleted the resource-cancellable-and-timeout branch February 1, 2016 16:29
@mrac
Copy link
Contributor Author

mrac commented Feb 11, 2016

@gkalpak It's nice to have it released already, thanks!

Still here remains a problem of how to distinguish between cancelled requests and timed-out requests. The latter might need different handling in most cases. Apparently both produce the same error response {status: -1, statusText: "", ...}

The solution would be to allow to pass a statusConfig to timeout-promise resolve value in $http. It could produce different error status and statusText. Currently timeout-promise resolve value is ignored entirely.

@gkalpak
Copy link
Member

gkalpak commented Feb 11, 2016

I don't think it's high priority, but I would be happy to review any PRs if anyone decided to submit them 😉

@mrac
Copy link
Contributor Author

mrac commented Feb 12, 2016

@gkalpak Great! So take a look:
feat($http,$resource): statusText resolved in timeout promise #14021

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

Successfully merging this pull request may close these issues.

3 participants