clojurepublish-subscribeclojurescriptcore.async

Whole publication is blocking


I'm following this guide to set up a pub/sub model in my ClojureScript application because I need multiple subscribers to all receive messages that are put on a channel.

Towards the bottom, the guide says:

It's worth noting that if a publication tries to pass to a channel that's not accepting values, the whole publication will block:

(def loser-chan (chan))
(sub our-pub :loser loser-chan)
(>!! input-chan {:msg-type :loser :text "I won't be accepted"})

Careful: this will return true and won't block, because the publication is taking values from input-chan. But inside the publication, a go block is hanging. The >!! of a :loser value won't block the main thread either, but all following will.

The moral of the story is: if you subscribe a channel to a publication, make sure it can accept values! You should be doing this anyway, but it's especially important when dealing with publications, because you might not have any inkling that something is wrong until some other topic is hanging.

I don't understand this, but I'm afraid I am running into the issue that is described there while trying to implement a generic function that can take any event and return a channel which will receive messages for that event:

(def socket-events (chan))
(def socket-pub (pub socket-events :event-type))

(defn on
  "Given a socket event type, returns a channel
  that subscribes to that event type on the
  socket publication."
  [event-type]
  (let [c (chan)]
    (sub socket-pub event-type c)
    c)))

It does what the guide describes: it works twice, then stops working.

I don't understand how the non-working example in the guide is different from the working examples. As far as I can tell, it looks exactly the same as the working output channel example, with the exception that it's listening for another event. But I thought the whole idea was that one should be able to do this.

What am I missing?


Solution

  • Assuming you mean with "it works twice", that the first put works and continues and the second one blocks, this is due to the (chan) you subscribed with. The warning in the wiki states, that the whole chain blocks, if there are consumers, that don't accept anymore.

    So what happes your first put dispatches into your (chan) (which can hold one item), but without a consumer, this blocks the whole chain.

    Depending on your usecase, you might want to use buffers inside the pub/sub or on the receiver-side.