Skip to content

Instantly share code, notes, and snippets.

@xaviervia
Last active December 20, 2016 22:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xaviervia/ffe5f94ff9da7ad6238e1713adfccbd0 to your computer and use it in GitHub Desktop.
Save xaviervia/ffe5f94ff9da7ad6238e1713adfccbd0 to your computer and use it in GitHub Desktop.
rest subscriber

Automatically retries until all three checks are solved

It starts out with:

const initialState = {
  checks: {
    one: undefined,
    two: undefined,
    three: undefined
  }
}

…and the idea is to get to:

const initialState = {
  checks: {
    one: Symbol.for('solved'),
    two: Symbol.for('solved'),
    three: Symbol.for('solved')
  }
}

In order to do that, three actions are dispatched when starting up the app, setting each of the marks in status Symbol.for('pending')

If a fetch call fails, the check will be set to Symbol.for('failed') via the FAILED action. Since the state is updated, the fetch effect will be called again. The fetch effect will find the updated check (from pending to failed) and trigger fetch again

const initialState = {
checks: {
one: undefined,
two: undefined,
three: undefined
}
}
const reducer = (state, action) => {
switch (action.type) {
case 'LOAD':
return {
...state,
checks: {
...state.checks,
[action.payload.checkName]: Symbol.for('pending')
}
}
case 'FAILED':
return {
...state,
checks: {
...state.checks,
[action.payload.checkName]: Symbol.for('failed')
}
}
case 'SOLVED':
return {
...state,
checks: {
...state.checks,
[action.payload.checkName]: Symbol.for('solved')
}
}
}
}
const fetchEffect = (prevState, cachedNext) => (state, next) => {
cachedNext = next
Object.keys(state.checked)
.filter((key) =>
state.checked[key] !== prevState.checked[key] &&
(
state.checked[key] === Symbol.for('pending') ||
state.checked[key] === Symbol.for('failed')
)
)
.forEach((key) => fetch(`/${key}`)
.then(() => cachedNext({ type: 'SOLVED', payload: { checkName: key } }))
.catch(() => cachedNext({ type: 'FAILED', payload: { checkName: key } }))
)
}
const app = (reducer, initialState, actions, effects) => {
const newState = actions.reduce(reducer, initialState)
const next = (action) => app(reducer, newState, [action], effects)
effects.forEach((effect) => effect(newState, next))
return app
}
app(
reducer,
initialState,
[
{ type: 'LOAD', payload: { checkName: 'one' } },
{ type: 'LOAD', payload: { checkName: 'two' } },
{ type: 'LOAD', payload: { checkName: 'three' } }
],
[
fetchEffect(initialState, () => {}),
(state) => console.log(state)
]
)
const express = require('express')
const app = express()
const {random} = Math
app.get('*', (_, res) => {
random() < 0.2
? res.sendStatus(404)
: res.sendStatus(200)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment