Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create fallback cmd #10

Open
kurtcorbett opened this issue Aug 4, 2017 · 1 comment
Open

Create fallback cmd #10

kurtcorbett opened this issue Aug 4, 2017 · 1 comment

Comments

@kurtcorbett
Copy link
Collaborator

Proposal

Create a cmd that takes any number of commands or composers (retry, either, etc.).

  • Upon failure of the first cmd the next one will be called and so on until one of them succeeds.
  • failure and success would be determined by a predicate callback provided by the caller.
  • If no predicate is defined, a failure would be anything that throws an error or returns a falsey value.
  • A default value or an error could be provided as the last argument
  • If no default value or error is provided, fallback with throw a generic error

Other possible names:
failover()

Signature

fallback(cmds, [predicate], [default])

Arguments

cmds: Array of cmds
predicate: (optional) callback function that returns a boolean determining if a cmd passed or failed
default: (optional) value or error that will be returned or thrown if all commands fail

Examples

Complex (maybe unrealistic) caching example

// getUserFriends.spec.js

testFn(getUserFriends, () => {
  const id = 123
  const friends = [ 'ross', 'joey', 'chandler' ]

  const $localCacheUser = cmds.getUserLocalCache(id)
  const $dbUser = cmds.getUser(id)
  const $getFacebookFriendsWithRetry = cmds.retry(cmds.getUserFacebookFriends(id), [ 100, 1000, 2000 ])
  const $setUserCache = cmds.setUserCache(id, { friends })
  const $setUserLocalCache = cmds.setUserLocalCache(id, { friends })
  const getUserFriendsCmd = cmds.fallback(
    $localCacheUser,
    $dbUser,
    $getFacebookFriendsWithRetry,
    {
      predicate: hasFriends,
      default: [],
    },
  )

  return args(id)
    .yieldCmd(getUserFriendsCmd).yieldReturns(friends)
    .yieldCmd([ $setUserCache, $setUserLocalCache ]).yieldReturns(null)
    .returns(friends)
})()
// getUserFriends.js

function * getUserFriends(id) {
  const $getLocalCacheUser = cmds.getUserLocalCache(id)
  const $getDbUser = cmds.getUser(id)
  const $getFacebookFriendsWithRetry = cmds.retry(cmds.getUserFacebookFriends(id), [ 100, 1000, 2000 ])

  const friends = yield cmds.fallback(
    $getLocalCacheUser,
    $getDbUser,
    $getFacebookFriendsWithRetry,
    {
      predicate: hasFriends,
      default: [],
    },
  )

  if (friends.length > 0) {
    yield [
      cmds.setUser(id, { friends }),
      cmds.setUserLocalCache(id, { friends }),
    ]
  }

  return friends
}

function hasFriends(result) {
  const friends = Array.isArray(result) ? result : result.friends
  return friends.length > 0
}
@michaeljacobdavis
Copy link
Collaborator

michaeljacobdavis commented Aug 6, 2017

@kurtcorbett I like it! @orourkedd added hit recently which is similar (checkout https://github.com/michaeljacobdavis/effects-as-data-universal/tree/hit#hit for the doc).

You could accomplish the default with an echo:

  const friends = yield cmds.hit(
    $getLocalCacheUser,
    $getDbUser,
    $getFacebookFriendsWithRetry,
    cmds.echo([])
  )

But wouldn't be able to do a custom predicate. @orourkedd thoughts on extending hit for a custom predicate vs creating this as a separate command?

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

No branches or pull requests

2 participants