Skip to content

Commit b0ebfe0

Browse files
author
Edgar mac
committed
readme: advanced cases
1 parent e9c0de1 commit b0ebfe0

6 files changed

+396
-23
lines changed

README.md

+298-22
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,42 @@ yarn add redux-action-retry
99
# Getting Started
1010
## Basic Configuration
1111

12-
```typescript
13-
import {
14-
createRetryMechanism,
15-
} from 'redux-action-retry';
12+
```ts
13+
import uuid from 'uuid/v4';
14+
import { REDUX_ACTION_RETRY } from 'redux-action-retry';
1615

16+
// actions to retry
17+
export const SEND_LOGS_TO_SERVER = 'SEND_LOGS_TO_SERVER';
18+
export const NOTIFY_ACTION = 'NOTIFY_ACTION';
19+
20+
// action creators
21+
export function sendLogsToServerActionCreator() {
22+
return {
23+
type: SEND_LOGS_TO_SERVER,
24+
// meta must be config
25+
meta: {
26+
[REDUX_ACTION_RETRY]: {
27+
// the id will be used to identify the action in the cache.
28+
id: uuid()
29+
}
30+
}
31+
}
32+
}
33+
```
34+
35+
```ts
1736
import {
1837
createStore,
1938
combineReducers,
2039
applyMiddleware,
2140
} from 'redux';
2241

23-
// actions to retry
24-
const SEND_LOGS_TO_SERVER = 'SEND_LOGS_TO_SERVER';
25-
const NOTIFY_ACTION = 'NOTIFY_ACTION';
42+
import { createRetryMechanism } from 'redux-action-retry';
43+
import { SEND_LOGS_TO_SERVER, NOTIFY_ACTION } from './actions';
2644

27-
const { reducer, reduxActionRetryMiddleware, stateKeyName } = createRetryMechanism({
45+
const { reducer, reduxActionRetryMiddlewares, stateKeyName } = createRetryMechanism({
2846
cache: {
47+
// action types are keys
2948
[SEND_LOGS_TO_SERVER]: {
3049
type: SEND_LOGS_TO_SERVER,
3150
},
@@ -37,45 +56,302 @@ const { reducer, reduxActionRetryMiddleware, stateKeyName } = createRetryMechani
3756

3857
export const store = createStore(
3958
combineReducers({
59+
// Use the stateKeyName as the key name of the reducer, as needed for the retry mechanism middlewares.
4060
[stateKeyName]: reducer
4161
}),
4262
applyMiddleware
4363
(
44-
...reduxActionRetryMiddleware,
64+
// Spread the middlewares
65+
...reduxActionRetryMiddlewares,
4566
)
4667
);
4768
```
4869

49-
## Basic Usage
70+
## Remove action from cache
5071

5172
When actions are dispatched, the middleware immediately caches the action, if the action is successful you can remove it dispatching a remove action.
5273

53-
```typescript
74+
```ts
5475
import { put } from 'redux-saga/effects'
55-
import {
56-
removeActionCreator,
57-
} from 'redux-action-retry';
76+
import { removeActionCreator } from 'redux-action-retry';
5877

5978
function* sendLogsToServer(action) {
60-
// domain logic
79+
// domain logic...
80+
// ...
6181

62-
// all good
82+
// if all good then remove from retry mechanism
6383
yield put(removeActionCreator(action))
6484
}
6585
```
6686

67-
When retrying is needed you can dispatch a retry all action
87+
## Retry actions
88+
89+
When retrying is needed you can dispatch a retry all action.
6890

69-
```typescript
91+
```ts
7092
import { put } from 'redux-saga/effects'
71-
import {
72-
retryAllActionCreator,
73-
} from 'redux-action-retry';
93+
import { retryAllActionCreator } from 'redux-action-retry';
7494

7595
function* appForeground() {
76-
// other actions
96+
// domain logic...
97+
// ...
7798

7899
// retry all cached actions
79100
yield put(retryAllActionCreator())
80101
}
102+
```
103+
104+
## Reset Store
105+
106+
```ts
107+
import {
108+
resetActionCreator,
109+
} from 'redux-action-retry';
110+
111+
function logout() {
112+
// domain logic...
113+
// ...
114+
115+
// reset the store for redux-action-retry
116+
dispatch(resetActionCreator())
117+
}
118+
```
119+
120+
# Advanced Usage
121+
## Cooldown
122+
![Without cooldown timeline](charts/basic_timeline.png)
123+
Without cooldown timeline
124+
125+
![With cooldown timeline](charts/basic_cooldown_timeline.png)
126+
With cooldown timeline
127+
128+
129+
The amount of time an action could take executing (**Flying time**) might be indicated, for example, by the timeout of a request, if a request is bound to fail after 30 seconds by timeout, then the action could be flying for at least 30 seconds.
130+
131+
Often when actions are dispatched, we wouldn't want them to be retried before we know they've succeeded or failed.
132+
133+
134+
### Configuration
135+
136+
```ts
137+
export const REQUEST_TIMEOUT = duration('PT30S');
138+
```
139+
140+
```ts
141+
import {
142+
createStore,
143+
combineReducers,
144+
applyMiddleware,
145+
} from 'redux';
146+
import { duration } from "moment";
147+
import { createRetryMechanism, Cooldown } from 'redux-action-retry';
148+
import { SEND_LOGS_TO_SERVER, NOTIFY_ACTION } from './actions';
149+
150+
const { reducer, reduxActionRetryMiddlewares, stateKeyName } = createRetryMechanism({
151+
cache: {
152+
[SEND_LOGS_TO_SERVER]: {
153+
type: SEND_LOGS_TO_SERVER,
154+
// cooldown config is per action
155+
cooldownTime: duration('PT31S'),
156+
},
157+
[NOTIFY_ACTION]: {
158+
type: NOTIFY_ACTION,
159+
// As a rule of thumb add a bit more of time to allow for actual code and framework delays.
160+
cooldownTime: duration('PT31S'),
161+
},
162+
extensions: [
163+
Cooldown,
164+
]
165+
},
166+
});
167+
168+
export const store = createStore(
169+
combineReducers({
170+
[stateKeyName]: reducer
171+
}),
172+
applyMiddleware
173+
(
174+
...reduxActionRetryMiddlewares,
175+
)
176+
);
177+
```
178+
179+
### Early response
180+
181+
![Cancel cooldown timeline](charts/cancel_cooldown_timeline.png)
182+
Cancel cooldown timeline
183+
184+
In the case of an early fail response we might want the action be to be retryable sooner than the cooldown time, so we might want to cancel it.
185+
186+
```ts
187+
import { put } from 'redux-saga/effects'
188+
import { cancelCooldownActionCreator } from 'redux-action-retry';
189+
190+
function* sendLogsToServer(action) {
191+
// domain logic...
192+
// ...
193+
194+
if(allGood) {
195+
yield put(removeActionCreator(action))
196+
} else {
197+
// in case of early fail
198+
yield put(cancelCooldownActionCreator(action))
199+
}
200+
}
201+
```
202+
203+
### Cool and Retry All utility
204+
205+
In case we want to Retry All without caring for the cooldown time, dispatch a **coolAndRetryAllActionCreator**.
206+
207+
```ts
208+
import { coolAndRetryAllActionCreator } from 'redux-action-retry';
209+
210+
function* rehydrate(action) {
211+
// domain logic...
212+
// ...
213+
214+
yield put(coolAndRetryAllActionCreator(action))
215+
}
216+
```
217+
218+
## Times
219+
220+
State without times:
221+
```json
222+
{"REDUX_ACTION_RETRY": {
223+
"cache": [{
224+
"action": {
225+
"type": "SEND_LOGS_TO_SERVER",
226+
"meta": {
227+
"REDUX_ACTION_RETRY": {
228+
"id": "3b2a7b5f-47f8-4774-af84-d28c5ecb61a7"
229+
}
230+
}
231+
},
232+
}]}}
233+
```
234+
State with times:
235+
```json
236+
{ "REDUX_ACTION_RETRY": {
237+
"cache": [{
238+
"action": {
239+
"type": "SEND_LOGS_TO_SERVER",
240+
"meta": {
241+
"REDUX_ACTION_RETRY": {
242+
"id": "3b2a7b5f-47f8-4774-af84-d28c5ecb61a7"
243+
}
244+
}
245+
},
246+
"times": 5
247+
}]}}
248+
```
249+
250+
In case you want to add a counter of the times an action have been retried, use the **Times** Extension.
251+
252+
### Configuration
253+
254+
```ts
255+
import {
256+
createStore,
257+
combineReducers,
258+
applyMiddleware,
259+
} from 'redux';
260+
import { duration } from "moment";
261+
import { createRetryMechanism, times } from 'redux-action-retry';
262+
import { SEND_LOGS_TO_SERVER, NOTIFY_ACTION } from './actions';
263+
264+
const { reducer, reduxActionRetryMiddlewares, stateKeyName } = createRetryMechanism({
265+
cache: {
266+
[SEND_LOGS_TO_SERVER]: {
267+
type: SEND_LOGS_TO_SERVER,
268+
},
269+
[NOTIFY_ACTION]: {
270+
type: NOTIFY_ACTION,
271+
},
272+
extensions: [
273+
times,
274+
]
275+
},
276+
});
277+
278+
export const store = createStore(
279+
combineReducers({
280+
[stateKeyName]: reducer
281+
}),
282+
applyMiddleware
283+
(
284+
...reduxActionRetryMiddlewares,
285+
)
286+
);
287+
```
288+
289+
### Use cases
290+
#### Debugging / reports
291+
In case of debugging or reading reports, having a count of how many times an action actually failed is very useful.
292+
293+
#### Optimistic response
294+
We might want to keep triggering one saga but not the reducer, in those cases we could add a middleware to consume the action based on the times counter.
295+
#### Cease retrying
296+
In case we want to cease retrying after a number of attempts we could add a middleware that dispatches a remove command based on the times counter.
297+
298+
## Time to live
299+
300+
In case we want to cease retrying after an amount of time, we could use **Time to live** extension.
301+
302+
Dead actions are prevented from retrying, but when to remove those from the cache is up to the user (might want to send for stats/reports).
303+
304+
### Configuration
305+
```ts
306+
import {
307+
createStore,
308+
combineReducers,
309+
applyMiddleware,
310+
} from 'redux';
311+
import { duration } from "moment";
312+
import { createRetryMechanism, TimeToLive } from 'redux-action-retry';
313+
import { SEND_LOGS_TO_SERVER, NOTIFY_ACTION } from './actions';
314+
315+
const { reducer, reduxActionRetryMiddlewares, stateKeyName } = createRetryMechanism({
316+
cache: {
317+
[SEND_LOGS_TO_SERVER]: {
318+
type: SEND_LOGS_TO_SERVER,
319+
// time to live config is per action
320+
timeToLive: duration('P3D')
321+
},
322+
[NOTIFY_ACTION]: {
323+
type: NOTIFY_ACTION,
324+
cooldownTime: duration('P1D'),
325+
},
326+
extensions: [
327+
TimeToLive,
328+
]
329+
},
330+
});
331+
332+
export const store = createStore(
333+
combineReducers({
334+
[stateKeyName]: reducer
335+
}),
336+
applyMiddleware
337+
(
338+
...reduxActionRetryMiddlewares,
339+
)
340+
);
341+
```
342+
343+
### How to remove dead actions
344+
345+
When we want to remove dead actions we dispatch a **collectGarbageActionCreator**.
346+
```ts
347+
import { collectGarbageActionCreator } from 'redux-action-retry';
348+
349+
function* rehydrate(action) {
350+
// domain logic...
351+
// ...
352+
353+
yield put(collectGarbageActionCreator(action))
354+
// we might want to collect garbage before issuing a retry all
355+
yield put(coolAndRetryAllActionCreator(action))
356+
}
81357
```

charts/basic_cooldown_timeline.png

66.4 KB
Loading

charts/basic_timeline.png

63.4 KB
Loading

charts/cancel_cooldown_timeline.png

70.2 KB
Loading

0 commit comments

Comments
 (0)