leonoel / missionary

A functional effect and streaming system for Clojure/Script
Eclipse Public License 2.0
630 stars 26 forks source link

Uncatchable NullPointerException on exception in reactor publisher #40

Closed mjmeintjes closed 2 years ago

mjmeintjes commented 2 years ago

I believe this issue is related to #39 . Running the following code gives me a NullPointerException, and the error handling around the reactor call is never called. I would expect the message "ERROR IS VISIBLE" to be printed, however I get the stacktrace below.

  (def mbx (ms/mbx))
  (do
    (def cancel
      ((ms/sp
        (try
          (ms/? (ms/reactor
                 (let [state (ms/stream! (ms/ap
                                          (let [r (ms/?> (ms/ap
                                                          (->> (repeat mbx)
                                                               ms/seed
                                                               ms/?>
                                                               ms/?)))]
                                            (if (= r 1)
                                              (throw (ex-info "Invalid" {:a 123}))
                                              r))))]
                   (ms/stream!
                    (ms/ap (println (ms/?> state)))))))
          (println "DONE")
          (catch Exception ex
            (println "ERROR IS VISIBLE")
            (throw ex))))
       prn prn))
    (mbx 2)
    (mbx 1))
Unhandled java.lang.NullPointerException
   (No message)

            Ambiguous.java:   45  missionary.impl.Ambiguous/more
            Ambiguous.java:   59  missionary.impl.Ambiguous$1/invoke
            Ambiguous.java:  115  missionary.impl.Ambiguous$3/invoke
              Mailbox.java:   27  missionary.impl.Mailbox/invoke
                      REPL:  384  mattsum.task-feed.statecharts/eval119791
                      REPL:  384  mattsum.task-feed.statecharts/eval119791
             Compiler.java: 7181  clojure.lang.Compiler/eval
             Compiler.java: 7171  clojure.lang.Compiler/eval
             Compiler.java: 7136  clojure.lang.Compiler/eval
                  core.clj: 3202  clojure.core/eval
                  core.clj: 3198  clojure.core/eval
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn/fn
                  AFn.java:  152  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                  core.clj:  667  clojure.core/apply
                  core.clj: 1977  clojure.core/with-bindings*
                  core.clj: 1977  clojure.core/with-bindings*
               RestFn.java:  425  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn
                  main.clj:  437  clojure.main/repl/read-eval-print/fn
                  main.clj:  437  clojure.main/repl/read-eval-print
                  main.clj:  458  clojure.main/repl/fn
                  main.clj:  458  clojure.main/repl
                  main.clj:  368  clojure.main/repl
               RestFn.java:  137  clojure.lang.RestFn/applyTo
                  core.clj:  667  clojure.core/apply
                  core.clj:  662  clojure.core/apply
                regrow.clj:   20  refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
               RestFn.java: 1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   84  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   56  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  152  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
                  AFn.java:   22  clojure.lang.AFn/run
               session.clj:  202  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  201  nrepl.middleware.session/session-exec/main-loop
                  AFn.java:   22  clojure.lang.AFn/run
               Thread.java:  832  java.lang.Thread/run
mjmeintjes commented 2 years ago

If I remove the mbx flow and replace it with m/seed, I get a NullPointerException, but this one is catchable. However, I would still expect that the error thrown (ex-info "Invalid") should be the one caught.

(do
    (def cancel
      ((ms/sp
        (try
          (ms/? (ms/reactor
                 (let [state (ms/stream! (ms/ap
                                          (let [r (ms/?> (ms/seed [2 1]))]
                                            (if (= r 1)
                                              (throw (ex-info "Invalid" {:a 123}))
                                              r))))]
                   (ms/stream!
                    (ms/ap (println (ms/?> state)))))))
          (println "DONE")
          (catch Exception ex
            (println "ERROR IS VISIBLE")
            (throw ex))))
       prn prn)))
ERROR IS VISIBLE
#error {
 :cause nil
 :via
 [{:type java.lang.NullPointerException
   :message nil
   :at [missionary.impl.Reactor signal "Reactor.java" 93]}]
 :trace
 [[missionary.impl.Reactor signal "Reactor.java" 93]
  [missionary.impl.Reactor emit "Reactor.java" 187]
  [missionary.impl.Reactor leave "Reactor.java" 210]
  [missionary.impl.Reactor context "Reactor.java" 361]
  [missionary.impl$context invokeStatic "impl.clj" 100]
  [missionary.impl$context invoke "impl.clj" 100]
  [missionary.core$reactor_call$fn__51676 invoke "core.cljc" 719]
  [missionary.impl.Sequential task "Sequential.java" 86]
  [missionary.impl$fiber_task invokeStatic "impl.clj" 39]
  [missionary.impl$fiber_task invoke "impl.clj" 39]
  [missionary.core$_QMARK_ invokeStatic "core.cljc" 172]
  [missionary.core$_QMARK_ invoke "core.cljc" 164]
  [mattsum.task_feed.statecharts$fn__119870$cr119857_block_1__119873 invoke "NO_SOURCE_FILE" 364]
  [cloroutine.impl$coroutine$fn__51204 invoke "impl.cljc" 60]
  [missionary.impl.Sequential step "Sequential.java" 49]
  [missionary.impl.Sequential <init> "Sequential.java" 61]
  [missionary.impl$sp invokeStatic "impl.clj" 32]
  [missionary.impl$sp invoke "impl.clj" 32]
  [cloroutine.impl$coroutine$fn__51204 invoke "impl.cljc" 65]
  [clojure.core$partial$fn__5857 invoke "core.clj" 2629]
  [clojure.lang.AFn applyToHelper "AFn.java" 156]
  [clojure.lang.RestFn applyTo "RestFn.java" 132]
  [clojure.lang.Compiler$InvokeExpr eval "Compiler.java" 3706]
  [clojure.lang.Compiler$DefExpr eval "Compiler.java" 457]
  [clojure.lang.Compiler eval "Compiler.java" 7186]
  [clojure.lang.Compiler eval "Compiler.java" 7170]
  [clojure.lang.Compiler eval "Compiler.java" 7136]
  [clojure.core$eval invokeStatic "core.clj" 3202]
  [clojure.core$eval invoke "core.clj" 3198]
  [nrepl.middleware.interruptible_eval$evaluate$fn__79437$fn__79438 invoke "interruptible_eval.clj" 87]
  [clojure.lang.AFn applyToHelper "AFn.java" 152]
  [clojure.lang.AFn applyTo "AFn.java" 144]
  [clojure.core$apply invokeStatic "core.clj" 667]
  [clojure.core$with_bindings_STAR_ invokeStatic "core.clj" 1977]
  [clojure.core$with_bindings_STAR_ doInvoke "core.clj" 1977]
  [clojure.lang.RestFn invoke "RestFn.java" 425]
  [nrepl.middleware.interruptible_eval$evaluate$fn__79437 invoke "interruptible_eval.clj" 87]
  [clojure.main$repl$read_eval_print__9110$fn__9113 invoke "main.clj" 437]
  [clojure.main$repl$read_eval_print__9110 invoke "main.clj" 437]
  [clojure.main$repl$fn__9119 invoke "main.clj" 458]
  [clojure.main$repl invokeStatic "main.clj" 458]
  [clojure.main$repl doInvoke "main.clj" 368]
  [clojure.lang.RestFn applyTo "RestFn.java" 137]
  [clojure.core$apply invokeStatic "core.clj" 667]
  [clojure.core$apply invoke "core.clj" 662]
  [refactor_nrepl.ns.slam.hound.regrow$wrap_clojure_repl$fn__97450 doInvoke "regrow.clj" 20]
  [clojure.lang.RestFn invoke "RestFn.java" 1523]
  [nrepl.middleware.interruptible_eval$evaluate invokeStatic "interruptible_eval.clj" 84]
  [nrepl.middleware.interruptible_eval$evaluate invoke "interruptible_eval.clj" 56]
  [nrepl.middleware.interruptible_eval$interruptible_eval$fn__79468$fn__79472 invoke "interruptible_eval.clj" 152]
  [clojure.lang.AFn run "AFn.java" 22]
  [nrepl.middleware.session$session_exec$main_loop__79700$fn__79704 invoke "session.clj" 202]
  [nrepl.middleware.session$session_exec$main_loop__79700 invoke "session.clj" 201]
  [clojure.lang.AFn run "AFn.java" 22]
  [java.lang.Thread run "Thread.java" 832]]}
leonoel commented 2 years ago

Fixed in b.22