hyperfiddle 2025-02-06

How to catch a button click and execute server & client Electric code without an e/Token? My issue with e/Token token is that if I consume the token with (t), it seems to interrupt any in-flight server code (that isn't offloaded). Maybe I'm doing something wrong here:

(when-some [t (dom/button (dom/text "New Order")
                 (let [e (dom/On "click" identity nil)
                       [t err] (e/Token e)]
                   t))]
  (let [order-id (e/server (create-order! conn seller-id))] ; this returns an id.
    (r/Navigate! ['/ ['Orders order-id]])
    (t))) ;; consuming token here breaks r/Navigate! because it interrupts the when-some.
whereas it works if I take out the (t), but it feels like I'm leaking memory. (dom/on "click" (fn [] clojure-only) nil)) <= how to run e/server or e/client code on click?

Dustin Getz (Hyperfiddle) 2025-02-06T20:28:17.992399Z

yes you def are leaking memory if you don't dispose the token

Dustin Getz (Hyperfiddle) 2025-02-06T20:30:31.406159Z

the point of the token is to deal with failure, latency, retry, so the sequence of effects here should be • button click, construct token • query server, render busy state, wait for result • check server result for success or failure • if failure: don't navigate, use token to inject error back into the button so user can try again • if success: navigate

Dustin Getz (Hyperfiddle) 2025-02-06T20:30:56.087919Z

> it seems to interrupt any in-flight server code (that isn't offloaded) this i don't understand

Dustin Getz (Hyperfiddle) 2025-02-06T20:31:11.754589Z

Oh, (t) doesn't have any causal dependency on the server result order-id, that's why

Dustin Getz (Hyperfiddle) 2025-02-06T20:31:58.629239Z

(case order-id ::success (r/Navigate!), ::failure (t err))

Thanks, that works! Lotta people dumber than even me are gonna have a hard time with that. I sort of know how Electric works and spent an hour trying to figure out how I was using r/Navigate! wrong, until I accidentally took out the token consumption. We are not very wired for the implicit asynchronicity. btw. is there a way to keep track of unconsumed tokens? Guaranteed this is gonna be a big source of memory leaks.

👀 1
Dustin Getz (Hyperfiddle) 2025-02-06T20:37:36.010929Z

git gud, sorry

😄 3

I do miss just being able to pass an e/fn to a dom/on "click" event

Dustin Getz (Hyperfiddle) 2025-02-06T20:38:20.143849Z

we will probably add try/catch at some point which will help make this more natural looking

it's almost like Electric needs its own async IDE

Dustin Getz (Hyperfiddle) 2025-02-06T20:39:00.512599Z

you can implement a backwards compatible API that uses "callbacks", but we just think it has too many problems, we certainly don't want to encourage buggy patterns

"deez purple codes will run at same time" (hard, I know)

like rainbow parens for async-executing lines would be cool. I would have spotted that independent (t) instantly

Dustin Getz (Hyperfiddle) 2025-02-06T20:40:16.873449Z

well, it's all async, every expression is maximally concurrent

do body is concurrently running every expression, I guess that's what got you?

Re leaks - wrap your token fn in a timeout, something like

(e/defn TimeoutToken [nm ms t]
  (when t
    (case (e/Task (m/sleep ms))
      (do
        (prn 'leak nm)
        (t))))
  t)

The token API is less glamorous for the easy case, we agree on that. But it brings immense benefits wrt composition

Dustin Getz (Hyperfiddle) 2025-02-07T00:13:23.077379Z

> is there a way to keep track of unconsumed tokens if you're correctly monitoring the token to render busy and failure states (as in the https://electric.hyperfiddle.net/tutorial/token_explainer), it will be very obvious that the token is undisposed because your button will be yellow

👍 1