livebook-dev / kino

Client-driven interactive widgets for Livebook

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Race condition when delaying Kino.JS.Live.call reply

jannikbecher opened this issue · comments

When creating a new kino and directly invoking a call with a delayed response the following error occurs:

** (exit) exited in: GenServer.call(#PID<0.757.0>, :test, 5000)
    ** (EXIT) time out
    (elixir 1.15.7) lib/gen_server.ex:1074: GenServer.call/3
    #cell:ljknscxzevb4x3mpuppagmq7oloh73s2:2: (file)
POC

Example

Mix.install([
  {:kino, "~> 0.11.0"}
])

Section

defmodule Test do
  use Kino.JS
  use Kino.JS.Live

  def new do
    Kino.JS.Live.new(__MODULE__, nil)
  end

  def test(kino) do
    Kino.JS.Live.call(kino, :test)
  end

  def init(nil, ctx) do
    {:ok, ctx}
  end

  def handle_connect(ctx) do
    {:ok, %{}, ctx}
  end

  def handle_call(:test, from, ctx) do
    broadcast_event(ctx, "ping", nil)
    {:noreply, assign(ctx, caller: from)}
  end

  def handle_event("pong", _data, ctx) do
    Kino.JS.Live.reply(ctx.assigns.caller, "TEST")
    {:noreply, ctx}
  end

  asset "main.js" do
    """
    export function init(ctx, data) {
      ctx.handleEvent("ping", () => {
        ctx.pushEvent("pong", null);
      });
    }
    """
  end
end
{:module, Test, <<70, 79, 82, 49, 0, 0, 15, ...>>, :ok}

This is not working

Test.new()
|> Test.test()

This is working

test = Test.new()
Test.test(test)
"TEST"

@jannikbecher this is expected, note that in order for the client-side code to receive the event, the kino needs to actually be rendered on the page and initialised, which is not the case in the first example :)

@jonatanklosko Ah I see. Is there a way to check whether the kino is rendered? :)

You can keep track of new clients in handle_connect, just keep in mind that if the notebook is opened in multiple tabs (or the same kino is returned from multiple cells), there will be multiple "renderings" :)