Fork me on GitHub
#missionary
<
2023-04-18
>
denik18:04:42

facing deadlocks after an unspecified duration from tasks started in this file https://github.com/lumberdev/tesserae/blob/master/src/tesserae/eval.clj#L311

denik18:04:11

see the defstates named *-listener

denik18:04:29

if backpressure is indeed the issue, how can this be solved? I would not want to drop computation using m/relieve

leonoel19:04:17

if it is a backpressure issue, the callback should throw and propagate to d/transact!

leonoel19:04:56

in this case the solution is to consume faster than production

denik19:04:51

not seeing any errors, instead the parts of the (electric) app deadlock requiring full app restart

leonoel19:04:18

is this a JVM deadlock ? you can check that with e.g visualvm

denik19:04:33

seems to be

denik19:04:36

never used visualvm

denik19:04:38

I guess it’s time

leonoel19:04:13

if visualvm detects a deadlock, please send stacktraces of interlocked threads

denik19:04:19

just ran it with a m/relieve wrapped around observe and ran into the same deadlock

leonoel19:04:59

can you check with missionary version forced to b.30 ?

denik19:04:50

just did, same issue

leonoel19:04:25

OK thank you for reporting. I have enough information to investigate

denik19:04:10

of course! do you think it’s likely that this is a missionary issue or should I keep digging in my userland code?

leonoel19:04:30

it is likely a missionary issue

denik20:04:00

it’s plausible. I just played more with my own code and was unable to repro the issue outside of missionary.

leonoel12:04:48

@U050CJFRU here is a workaround. Here https://github.com/lumberdev/tesserae/blob/68b36f764a6839eca0e6134619f7e190fbfbe1a2/src/tesserae/ui/views.cljc#L206 replace this watch with (new (async-watch db/conn))

(defn async-watch [!x]
  (m/sample deref
    (m/ap (m/?> (m/relieve {}
                  (m/observe
                    (fn [!]
                      (! nil)
                      (add-watch !x ! (fn [! _ _ _] (! nil)))
                      #(remove-watch !x !)))))
      (m/? (m/via m/cpu !x)))))
The problem is datalevin calls the conn watches while holding the transaction lock, this can interlock with the reactor lock when : • one thread transacts db outside electric, then propagates the new db state to electric • another thread propagates a change inside electric, then transacts db async-watch ensures the datalevin lock is released when the new db state is propagated to electric. I'm still not sure if the bug is in datalevin or missionary, I'll keep this scenario in mind for the next iteration.

❤️ 2
denik19:04:42

thanks @U053XQP4S getting

#error {
 :cause Undefined continuous flow.
 :via
 [{:type java.lang.Error
   :message Undefined continuous flow.
   :at [missionary.impl.Continuous push Continuous.java 319]}]

denik19:04:53

(e/defn App []
  (e/client
    (dom/div
      (dom/props {:class [:flex :flex-col :w-100vw :h-100vh :overflow-hidden]})
      (e/server
        (binding [g/db (new (eu/async-watch db/conn))]
          (new Nav)
          (new Route))))))

leonoel19:04:18

sorry, my bad

leonoel19:04:20

(defn async-watch [!x]
  (m/sample deref
    (m/reductions {} !x
      (m/ap (m/?> (m/relieve {}
                    (m/observe
                      (fn [!]
                        (add-watch !x ! (fn [! _ _ _] (! nil)))
                        #(remove-watch !x !)))))
        (m/? (m/via m/cpu !x))))))

denik19:04:32

thank you! will test and report back!!

👍 1
denik15:04:23

so far so good

denik05:04:32

Heapdump downloadable near end of the thread