Giter VIP home page Giter VIP logo

Comments (15)

mallt avatar mallt commented on June 8, 2024

I've been able to reproduce cider issue 2138 on my machine and can confirm it is related to printing in a background thread.

With the nrepl version before PR #86 the "yep" has a missing id:

(sess {:id 11
       :op "load-file"
       :file "(ns quil-test.core
  (:require [quil.core :as q]))
(defn print-setup []
  (printf \"yep\")
  (flush))
(q/defsketch test-print
  :setup print-setup
  :size [100 100]) "})
;; => ({:id 11, :session "de6ce1fb-4a11-4dc8-b5d8-ec3f45ac914b", :value "#'quil-test.core/test-print"}
;;     {:out "yep", :session "de6ce1fb-4a11-4dc8-b5d8-ec3f45ac914b"}
;;     {:id 11, :session "de6ce1fb-4a11-4dc8-b5d8-ec3f45ac914b", :status ["done"]})

With the version of the PR branch the "yep" gets an id:

(sess {:id 12
       :op "load-file"
       :file "(ns quil-test.core
  (:require [quil.core :as q]))
(defn print-setup []
  (printf \"yep\")
  (flush))
(q/defsketch test-print
  :setup print-setup
  :size [100 100]) "})
;; => ({:id 12, :session "78d3cdbe-5d3f-4937-81fe-c25398228a41", :value "#'quil-test.core/test-print"}
;;     {:id 12, :out "yep", :session "78d3cdbe-5d3f-4937-81fe-c25398228a41"}
;;     {:id 12, :session "78d3cdbe-5d3f-4937-81fe-c25398228a41", :status ["done"]})

As discussed with @vspinu it's dangerous however to use the *msg* reference since long running background threads can start using the message ids of more recent incoming nrepl messages and this may lead to responses getting linked to the wrong message id.

Would it make sense to use a fixed id for background thread printing? Or would that confuse the clients even more than a missing id?

from nrepl.

vspinu avatar vspinu commented on June 8, 2024

Would it make sense to use a fixed id for background thread printing?

Yeh, that's just equivalent to nil. At least now, all nREPL front-ends deal somehow with nils. When you start suddenly sending -1` it will create havoc for no good reason.

from nrepl.

bbatsov avatar bbatsov commented on June 8, 2024

CIDER blows up for such responses (as expected, because its response handlers are attached to request ids), so this is something that we really need to resolve one way or another. I'm certain we can find some way to infer the id of the original request in such cases.

from nrepl.

arichiardi avatar arichiardi commented on June 8, 2024

My 2c - if I understand things correctly.

If the request id tracks the lifespan of a request and the lifespan of the background thread is longer, then it makes sense for them to have a nil in it which signals that there are things we do not want/can't track.

from nrepl.

bbatsov avatar bbatsov commented on June 8, 2024

Why so? I can't imagine how can something like this be good for the clients. You start getting some random messages and you have no idea what to do with them or when they originated from. That's clearly a major problem. Sure, you can install some fallback handlers for such orphaned messages, but this doesn't sound like a proper solution to me.

Not to mention that any request can potentially originate in extra responses after you've received :done, so that's not really a big deal.

As discussed with @vspinu it's dangerous however to use the msg reference since long running background threads can start using the message ids of more recent incoming nrepl messages and this may lead to responses getting linked to the wrong message id.

I guess one approach to solving this would be to not recycle any of the background threads, right? Then having the msg as a thread-local variable should be safe.

from nrepl.

arichiardi avatar arichiardi commented on June 8, 2024

Yep just was saying is that it seems a problem of semantics and lifecycle. Of course if you are in control of starting the threads you can bind the id at spawn time.

It looks like we are saying the same thing ๐Ÿ˜„

from nrepl.

mallt avatar mallt commented on June 8, 2024

If we get a request that starts a thread itself, like this one f.ex.:

{:id 10
 :op "eval"
 :code "(do
        (println \"before\")
        (doto (Thread.
               (fn []
                 (Thread/sleep (rand 500))
                 (println \"in thread\")))
          (.start)
          (.join))
        (println \"after\"))"}

is there a way of binding the message id to that thread?

When I was looking into this it seemed altering the var root was the only option, but maybe I missed something. Thanks!

from nrepl.

mallt avatar mallt commented on June 8, 2024

I'm afraid I'm stuck with this problem.

@bbatsov @arichiardi Any help would be greatly appreciated. Thanks!

from nrepl.

mallt avatar mallt commented on June 8, 2024

@cgrand Could you perhaps shed some light on this problem? Thanks!

from nrepl.

cgrand avatar cgrand commented on June 8, 2024

Here's what I get from a quick read, please tell me if I'm wrong:

Maybe a race condition with the atom watch? (in cider-nrepl out.clj).

from nrepl.

mallt avatar mallt commented on June 8, 2024

Thank you for checking this so quickly! When looking purely to nREPL indeed both *msg* and *out* are not bound in background threads. So if something is printed in a background thread nREPL will not capture this, and also will not know by which incoming message the printing was requested.

Would there be a way to evaluate eval operations in an "isolated" environment in which we can bind both *msg* and *out* even in background threads?

from nrepl.

cgrand avatar cgrand commented on June 8, 2024

Would there be a way to evaluate eval operations in an "isolated" environment in which we can bind both msg and out even in background threads?

The crux of the problem is that those threads live outside of your isolated env. So it would mean putting everything in the isolated env...

If you want to catch everything then using System/set(Out|Err) is the way to go. There's "just" a subtle bug in the cider-nrepl implementation.

Shouldn't such a feature be part of nrepl proper? It's about basic stream handling.

from nrepl.

bbatsov avatar bbatsov commented on June 8, 2024

Shouldn't such a feature be part of nrepl proper? It's about basic stream handling.

Yeah, it should be. At the time when this was added to cider-nrepl I didn't have the option to change nREPL itself, so I had to get creative. For the same reason cider-nrepl currently has a pprint middleware (as before nREPL 0.5 the printer was hardcoded we couldn't simply instruct the server which printer to use).

At this point I certainly think we should just handle the out/err better in nREPL itself.

from nrepl.

cichli avatar cichli commented on June 8, 2024

Since b65567b we no longer rely on *msg* to determine the response ID โ€“ย instead we create new PrintWriters for each evaluation which close over the value of the ID. So if you're manually conveying *out* to some other thread and printing to it there, the responses will now at least correspond to the evaluation that captured and conveyed the value of *out*.

For usage of the root values of *out* and *err*, or of System/out and System/err, see #119.

from nrepl.

mallt avatar mallt commented on June 8, 2024

That's really great, thanks a lot @cichli!

I've checked the related cider issue 2138 with the latest cider and I confirm no more "id nil" errors are thrown. Thanks again!

from nrepl.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.