{"action":"created","issue":{"url":"https://api.github.com/repos/cujojs/most/issues/191","labels_url":"https://api.github.com/repos/cujojs/most/issues/191/labels{/name}","comments_url":"https://api.github.com/repos/cujojs/most/issues/191/comments","events_url":"https://api.github.com/repos/cujojs/most/issues/191/events","html_url":"https://github.com/cujojs/most/pull/191","id":129647295,"number":191,"title":"Make error architecture less aggressive","user":{"login":"briancavalier","id":90518,"avatar_url":"https://avatars.githubusercontent.com/u/90518?v=3","gravatar_id":"","url":"https://api.github.com/users/briancavalier","html_url":"https://github.com/briancavalier","followers_url":"https://api.github.com/users/briancavalier/followers","following_url":"https://api.github.com/users/briancavalier/following{/other_user}","gists_url":"https://api.github.com/users/briancavalier/gists{/gist_id}","starred_url":"https://api.github.com/users/briancavalier/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/briancavalier/subscriptions","organizations_url":"https://api.github.com/users/briancavalier/orgs","repos_url":"https://api.github.com/users/briancavalier/repos","events_url":"https://api.github.com/users/briancavalier/events{/privacy}","received_events_url":"https://api.github.com/users/briancavalier/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2016-01-29T02:39:51Z","updated_at":"2016-02-01T20:26:33Z","closed_at":"2016-01-29T12:17:15Z","pull_request":{"url":"https://api.github.com/repos/cujojs/most/pulls/191","html_url":"https://github.com/cujojs/most/pull/191","diff_url":"https://github.com/cujojs/most/pull/191.diff","patch_url":"https://github.com/cujojs/most/pull/191.patch"},"body":"The error architecture was slightly too aggressive, allowing `recoverWith` to recover from errors that occur later in the sink chain.  It should only recover from errors that occur earlier.  The specific change in this PR, while perhaps slightly counterintuitive at first, makes error handling more intuitive for users.\r\n\r\nUsing the words \"backwards\" and \"forwards\", and \"before\" and \"after\" is a little weird, but, imho, makes for a good mental model.\r\n\r\n#### Source and sink chains\r\n\r\nApplying combinators to a stream effectively composes a *source chain* that defines the behavior of the stream.  When an observer begins observing a stream, a \"run\" message is sent \"backwards\" through the source chain, from the observer to the ultimate producer source--the one that will produce events in the first place.  As it travels, that message builds up a *sink chain*, analogous to the source chain.  The producer begins producing events.  With the exception of a few combinators, events then propagate *synchronously* \"forward\" through the sink chain.\r\n\r\n#### Event and exception propagation\r\n\r\nEach event propagation is effectively a synchronous call stack.  If an exception is thrown during event synchronous propagation, it will stop the propagation and travel \"backwards\" through the sink chain, unwinding the call stack (this bit is important).  If nothing catches it, it will reach the producer, and then finally, the scheduler.  The scheduler will catch it and send the error \"forward\" through the sink chain again (using the `error` channel).\r\n\r\nThe \"backward\" propagation of thrown exceptions through the sink chain allowed an error in a later sink to propagate back past `recoverWith`, ultimately hit the scheduler, which then sent it \"forward\" again, allowing `recoverWith` to intercept it and recover.\r\n\r\nAllowing `recoverWith` to recover from errors that happen \"after\" it in the sink chain is unintuitive: a particular `recoverWith` should only be able to see errors that happen \"before\" it.\r\n\r\n#### Solution\r\n\r\nThe solution is also somewhat counterintuitive.  As an exception travels \"backwards\" through the sink chain, if it arrives at a `recoverWith` node, that `recoverWith` will catch it and immediately send it forward using the `error` channel.\r\n"},"comment":{"url":"https://api.github.com/repos/cujojs/most/issues/comments/178171240","html_url":"https://github.com/cujojs/most/pull/191#issuecomment-178171240","issue_url":"https://api.github.com/repos/cujojs/most/issues/191","id":178171240,"user":{"login":"unscriptable","id":46133,"avatar_url":"https://avatars.githubusercontent.com/u/46133?v=3","gravatar_id":"","url":"https://api.github.com/users/unscriptable","html_url":"https://github.com/unscriptable","followers_url":"https://api.github.com/users/unscriptable/followers","following_url":"https://api.github.com/users/unscriptable/following{/other_user}","gists_url":"https://api.github.com/users/unscriptable/gists{/gist_id}","starred_url":"https://api.github.com/users/unscriptable/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/unscriptable/subscriptions","organizations_url":"https://api.github.com/users/unscriptable/orgs","repos_url":"https://api.github.com/users/unscriptable/repos","events_url":"https://api.github.com/users/unscriptable/events{/privacy}","received_events_url":"https://api.github.com/users/unscriptable/received_events","type":"User","site_admin":false},"created_at":"2016-02-01T20:26:33Z","updated_at":"2016-02-01T20:26:33Z","body":"o_O :)"}}