Skip to content

Commit

Permalink
Merge pull request #33 from kouhin/feature/retryit
Browse files Browse the repository at this point in the history
use retryit and babel-runtime
  • Loading branch information
kouhin authored Mar 7, 2017
2 parents 9097531 + 9792547 commit 9e49b97
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 116 deletions.
5 changes: 4 additions & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"presets": [
"es2015"
"env"
],
"plugins": [
"transform-runtime"
]
}
9 changes: 4 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,8 @@
"babel-cli": "^6.18.0",
"babel-core": "^6.20.0",
"babel-eslint": "^7.1.1",
"babel-loader": "^6.2.10",
"babel-plugin-transform-runtime": "^6.15.0",
"babel-preset-es2015": "^6.18.0",
"babel-preset-stage-0": "^6.16.0",
"babel-preset-env": "^1.2.1",
"chai": "^3.5.0",
"eslint-config-airbnb-deps": "^14.0.0",
"isparta": "^4.0.0",
Expand All @@ -56,8 +54,9 @@
"sinon": "^1.17.6"
},
"dependencies": {
"async": "^2.1.4",
"lodash": "^4.17.2"
"babel-runtime": "^6.23.0",
"lodash": "^4.17.2",
"retryit": "^1.0.0"
},
"eslintConfig": {
"extends": "eslint-config-airbnb",
Expand Down
42 changes: 18 additions & 24 deletions src/Task.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import asyncify from 'async/asyncify';
import retry from 'async/retry';
import assign from 'lodash/assign';
import retryit from 'retryit';

import { loadFailure, loadSuccess } from './actions';
import { isAction } from './utils';
Expand All @@ -12,11 +10,11 @@ export default class Task {
throw new Error('action must be a plain object');
}

this.context = assign({}, context, {
this.context = Object.assign({}, context, {
action: monitoredAction,
});

this.params = assign({}, {
this.params = Object.assign({}, {
success({ action }) {
throw new Error('success() is not implemented', action.type);
},
Expand All @@ -35,8 +33,8 @@ export default class Task {
}, params);
}

execute(options = {}, callback) {
const opts = assign({}, DEFAULT_OPTIONS, options);
execute(options = {}) {
const opts = Object.assign({}, DEFAULT_OPTIONS, options);

const context = this.context;
const dispatch = context.dispatch;
Expand All @@ -51,37 +49,33 @@ export default class Task {
const disableInternalAction = options.disableInternalAction;

if (!shouldFetch(context)) {
callback(null, null); // load nothing
if (!disableInternalAction) {
const successAction = loadSuccess(context.action);
dispatch(successAction);
}
return;
return Promise.resolve();
}

dispatch(loading(context));

// Retry
const asyncFetch = asyncify(fetch);
retry({
return retryit({
times: opts.retryTimes,
interval: opts.retryWait,
}, (retryCb) => {
asyncFetch(context, retryCb);
}, (err, result) => {
if (err) {
}, () => Promise.resolve(fetch(context)))
.then((result) => {
const successAction = success(context, result);
if (!disableInternalAction) {
dispatch(loadSuccess(context.action, result));
}
return dispatch(successAction);
})
.catch((err) => {
const errorAction = error(context, err);
if (!disableInternalAction) {
dispatch(loadFailure(context.action, err));
}
callback(null, dispatch(errorAction));
return;
}
const successAction = success(context, result);
callback(null, dispatch(successAction));
if (!disableInternalAction) {
dispatch(loadSuccess(context.action, result));
}
});
return dispatch(errorAction);
});
}
}
3 changes: 1 addition & 2 deletions src/TaskDescriptor.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import isEqual from 'lodash/isEqual';
import assign from 'lodash/assign';

import Task from './Task';
import { DEFAULT_OPTIONS } from './constants';
Expand All @@ -8,7 +7,7 @@ export default class TaskDescriptor {
constructor(pattern, params, options = {}) {
this.pattern = pattern;
this.params = params;
this.options = assign({}, DEFAULT_OPTIONS, options);
this.options = Object.assign({}, DEFAULT_OPTIONS, options);
if (this.options.retryTimes < 1) {
this.options.retryTimes = 1;
}
Expand Down
28 changes: 11 additions & 17 deletions src/createDataLoaderMiddleware.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import findKey from 'lodash/findKey';
import find from 'lodash/find';
import isEqual from 'lodash/isEqual';
import assign from 'lodash/assign';
import flattenDeep from 'lodash/flattenDeep';
import get from 'lodash/get';
import isInteger from 'lodash/isInteger';

import { REDUX_DATALOADER_ACTION_ID } from './constants';

Expand All @@ -27,10 +25,14 @@ export default function createDataLoaderMiddleware(

const middleware = ({ dispatch, getState }) => {
middleware.runningTasks = {};
const ctx = assign({}, withArgs, {
dispatch,
getState,
});
const ctx = Object.assign(
{},
withArgs,
{
dispatch,
getState,
},
);

return next => (receivedAction) => {
// eslint-disable-next-line no-underscore-dangle
Expand All @@ -53,25 +55,17 @@ export default function createDataLoaderMiddleware(
}

// Priority: Action Meta Options > TaskDescriptor Options > Middleware Options
const options = assign(
const options = Object.assign(
{},
middlewareOpts,
taskDescriptor.options,
get(asyncAction, 'meta.options', {}),
);

const task = taskDescriptor.newTask(ctx, action);
const runningTask = new Promise((resolve, reject) => {
task.execute(options, (err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
const runningTask = task.execute(options);

if (isInteger(options.ttl) && options.ttl > 0) {
if (Number.isInteger(options.ttl) && options.ttl > 0) {
const key = uniqueId(`${action.type}__`);
middleware.runningTasks[key] = { action, promise: runningTask };
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
Expand Down
72 changes: 34 additions & 38 deletions test/TaskDescriptor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,17 @@ describe('DataLoderTaskDescriptor', () => {
payload: {
userId: 25,
},
}).execute({}, (err) => {
if (err) {
done(err);
return;
}
expect(loadingSpy).to.have.been.calledOnce;
expect(shouldFetchSpy).to.have.been.calledOnce;
expect(fetchSpy).to.have.been.calledOnce;
expect(successSpy).to.have.been.calledOnce;
expect(errorSpy).to.have.not.been.called;
sinon.assert.callOrder(shouldFetchSpy, fetchSpy, successSpy);
done();
}).catch(done);
})
.execute({})
.then(() => {
expect(loadingSpy).to.have.been.calledOnce;
expect(shouldFetchSpy).to.have.been.calledOnce;
expect(fetchSpy).to.have.been.calledOnce;
expect(successSpy).to.have.been.calledOnce;
expect(errorSpy).to.have.not.been.called;
sinon.assert.callOrder(shouldFetchSpy, fetchSpy, successSpy);
done();
}).catch(done);
});

it('loading -> shouldFetch(return false) -> noop', (done) => {
Expand Down Expand Up @@ -88,18 +86,17 @@ describe('DataLoderTaskDescriptor', () => {
payload: {
userId: 25,
},
}).execute({}, (err, result) => {
if (err) {
done(err);
return;
}
expect(shouldFetchSpy).to.have.been.calledOnce;
expect(loadingSpy).to.have.not.been.called;
expect(fetchSpy).to.have.not.been.calledOnce;
expect(successSpy).to.have.not.been.called;
expect(errorSpy).to.have.not.been.called;
done(null, result);
});
})
.execute({})
.then((result) => {
expect(shouldFetchSpy).to.have.been.calledOnce;
expect(loadingSpy).to.have.not.been.called;
expect(fetchSpy).to.have.not.been.calledOnce;
expect(successSpy).to.have.not.been.called;
expect(errorSpy).to.have.not.been.called;
done(null, result);
})
.catch(done);
});

it('loading -> shouldFetch -> fetch -> error', (done) => {
Expand Down Expand Up @@ -127,18 +124,17 @@ describe('DataLoderTaskDescriptor', () => {
payload: {
userId: 25,
},
}).execute({}, (err, result) => {
if (err) {
done(err);
return;
}
expect(loadingSpy).to.have.been.calledOnce;
expect(shouldFetchSpy).to.have.been.calledOnce;
expect(fetchSpy).to.have.been.calledOnce;
expect(successSpy).to.have.not.been.called;
expect(errorSpy).to.have.been.calledOnce;
sinon.assert.callOrder(shouldFetchSpy, fetchSpy, errorSpy);
done(null, result);
});
})
.execute({})
.then((result) => {
expect(loadingSpy).to.have.been.calledOnce;
expect(shouldFetchSpy).to.have.been.calledOnce;
expect(fetchSpy).to.have.been.calledOnce;
expect(successSpy).to.have.not.been.called;
expect(errorSpy).to.have.been.calledOnce;
sinon.assert.callOrder(shouldFetchSpy, fetchSpy, errorSpy);
done(null, result);
})
.catch(done);
});
});
2 changes: 1 addition & 1 deletion test/createDataLoaderMiddleware.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ describe('createDataLoaderMiddleware', () => {
return store.dispatch(userActions.fetchUserRequest('tom'));
})
.then((result) => {
expect(result).to.be.equal(null);
expect(result).to.be.equal(undefined);
return store.dispatch(userActions.fetchUserRequest('tom'));
})
.then(() => {
Expand Down
28 changes: 0 additions & 28 deletions webpack.config.js

This file was deleted.

0 comments on commit 9e49b97

Please sign in to comment.