jarohen / chord

A library designed to bridge the gap between the triad of CLJ/CLJS, web-sockets and core.async.
439 stars 40 forks source link

#6: Fix up error handling #16

Closed charles-dyfis-net closed 10 years ago

charles-dyfis-net commented 10 years ago
charles-dyfis-net commented 10 years ago

This one now looks pretty good on my end (after rather a lot of interim revisions). Feedback appreciated.

charles-dyfis-net commented 10 years ago

...note: on current dev-channel Chrome, no data attribute is available on error objects, and the reason attribute for a connection-failed operation is frequently an empty string.

This appears to be by design and intent, and is likely to be the case on other browsers in the future if not already so -- best practices for WebSockets implementations suggest restricting information about the nature of a connection or negotiation failure, to prevent websockets from being used to implement port scanners.

jarohen commented 10 years ago

Hi Charles,

Thanks for all your work on this, I really appreciate it :)

I should have chance to look over the PR tomorrow, will let you know!

James

jarohen commented 10 years ago

Thanks for the PR - I've got some initial feedback and some thoughts:

Thanks again,

James

charles-dyfis-net commented 10 years ago

Howdy, James --

Thank you for the time and feedback.

jarohen commented 10 years ago

To be honest, I think it's going to have to be a 0.4 release anyway - one of the changes I'd like to make is that the initial channel returns either {:ws-chan chan} or {:error error} - otherwise I don't think we'd be fixing the original problem ;)

Having said that, hopefully we can keep the state machine implementation far enough away from the public API s.t. there's no breaking changes caused by the change in the internals - will see if it's possible...

charles-dyfis-net commented 10 years ago

I can't argue with you that passing back a channel which yields an error and then closes could be a bit misleading if the user has been promised that any yielded channel passed will represent an open socket; the approach presently taken in this PR is an attempt to do what we can within the bounds of compatibility with the existing API.

If we're willing to lose the ability to pass back such metadata as is available (which, given how little metadata is available about connection failures to deter port scanner development, I'd argue is not much loss), simply closing the initial channel rather than passing back any return channel would be a significant improvement on existing behavior which would avoid breaking any promises made by the 0.3.x API, allowing 0.4.x (with its breaking changes, and more detailed error messages) to follow later.

jarohen commented 10 years ago

Even closing the channel would be a breaking change though - i.e. the channel yielding nil rather than not yielding a value. It's quite reasonable for callers in 0.3.x to assume that (<! (ws-ch "...")) will never return nil (given that, currently, it will hang - at the moment it's up to the caller to wrap it in a timeout, which obviously isn't ideal!). For example:

(go
  (let [socket (ws-ch "ws://localhost:3000/ws")
        [v c] (a/alts! [socket (timeout 2000)])]
    (if (= c socket)
      (js/console.log (<! v))
      (js/console.log "timed out"))))

is perfectly valid under 0.3.x, but would break if we closed the initial channel on error.

I'd prefer to call such a release 0.4.x even if the breaking change is slight, just in case someone does depend on this behaviour - better to flag it and document it in the changelog than have someone upgrade an incremental version and get an NPE-like surprise.

jarohen commented 10 years ago

In other news, I've made a few other changes (mostly things I've been meaning to do for a while!):

The changes are on the 'connection-error-handling' branch in my repo.

James

charles-dyfis-net commented 10 years ago

Howdy --

I've updated my client code to use 0.4.0-SNAPSHOT, as implemented in the connection-error-handling branch, and it appears to play well. (Reworking the PR seems a dubious endeavor now that there's a substantial amount of new work developed on top of it; is this still something you'd like to see?)

That said, it looks like the [org.clojure/tools.reader "0.8.4"] dependency here conflicts rather badly with clojurescript 0.0-2202 (which depends on 0.8.3, and generates code which fails at runtime with 0.8.4).

jarohen commented 10 years ago

I've updated my client code to use 0.4.0-SNAPSHOT, as implemented in the connection-error-handling branch, and it appears to play well. (Reworking the PR seems a dubious endeavor now that there's a substantial amount of new work developed on top of it; is this still something you'd like to see?)

That's good :) Yes, agreed - no need to worry. I'll cut an rc1 today and sanity test it on a few of the projects that use it. Think it's then just the ChangeLog that needs updating, and we're good for a stable release.

That said, it looks like the [org.clojure/tools.reader "0.8.4"] dependency here conflicts rather badly with clojurescript 0.0-2202 (which depends on 0.8.3, and generates code which fails at runtime with 0.8.4).

I'm never sure whether to include a tools.reader dependency - sometimes it's required, sometimes a specific version is required, sometimes it doesn't matter, sometimes its inclusion breaks things horribly... sigh

I think Chord does need a tools.reader dep - if only for the people who only use the CLJ side without a ClojureScript dependency - the question is 'which one?'. I'll try out 0.8.3 as you suggest and see what happens!

Thanks,

James

jarohen commented 10 years ago

The fix to use 0.8.3 seems to be fine - I've just deployed a 0.4.0-rc1 release.

Could you let me know whether this works for you?

Thanks,

James

charles-dyfis-net commented 10 years ago

The release candidate works nicely. :)

jarohen commented 10 years ago

Excellent, thanks - I've just deployed 0.4.0.

Thank you for all your help with this release, it's much appreciated!

James