Stipple.jl icon indicating copy to clipboard operation
Stipple.jl copied to clipboard

0.25.20 breaks asynchronous tasks in reactive code blocks

Open PGimenez opened this issue 2 years ago • 6 comments
trafficstars

I have this code that runs a @task in which a counter gets increased each second. It worked in 0.25.15, but after upgrading to 0.20.20 it stops working.

using GenieFramework
@genietools 

@handlers begin
    p = @task 1+1
    @in x = 0.00
    @onchange isready begin
        if !istaskstarted(p) || istaskdone(p) 
            p = @task begin
                println("Task started")
                while x <= 100
                    x = x + 1
                    sleep(1)
                end
            end
            schedule(p)
        end
    end
end

function ui()
        bignumber("Counter", :x)
end

@page("/", ui)
Server.isrunning() || Server.up()

this is the error I'm getting on 0.20.25 and Julia 1.8.5

┌ Error: 2023-02-15 20:56:50 Error attempting to invoke handler 3 for field Reactive{Bool}(Observable(true), 1, false, false, "") with value true
└ @ Stipple ~/.julia/packages/Stipple/Ird4L/src/stipple/mutators.jl:36
┌ Error: 2023-02-15 20:56:50 UndefVarError(:p)
└ @ Stipple ~/.julia/packages/Stipple/Ird4L/src/stipple/mutators.jl:37

PGimenez avatar Feb 15 '23 19:02 PGimenez

I think @hhaensel can look at it. Can you check if it work on master with changes helmut made for kw. Not sure I understand the error

AbhimanyuAryan avatar Feb 16 '23 05:02 AbhimanyuAryan

I know what happened. You are using a local variable in handlers which I had not thought of when I generalised the Reactive API. I shall address this in a future release. Meanwhile an easy work around is to define a private field instead of a local variable:

@app begin
    @private p = @task 1+1
    @in x = 0.00
    @onchange isready begin
        if !istaskstarted(p) || istaskdone(p) 
            p = @task begin
                println("Task started")
                while x <= 100
                    x = x + 1
                    sleep(1)
                end
            end
            schedule(p)
        end
    end
end

Note, that I have used @appinstead of @handlers which clears the variable cache, so that you can rename variables without having old names trailing in the model.

hhaensel avatar Feb 16 '23 08:02 hhaensel

I also enhanced @handlers so that you can also declare non_reactive fields:

@app begin
    @private non_reactive p = @task 1+1
    @in x = 0.00
    @onchange isready begin
        if !istaskstarted(p) || istaskdone(p) 
            p = @task begin
                println("Task started")
                while x <= 100
                    x = x + 1
                    sleep(1)
                end
            end
            schedule(p)
        end
    end
end

hhaensel avatar Feb 16 '23 10:02 hhaensel

Should the official recommendation (and demos) be to always use @app instead of @handlers? Or why don't we replace @app with @handlers at code level so all codebases get automatically migrated to the @app features?

essenciary avatar Feb 16 '23 10:02 essenciary

I explained in detail in #159.

In my eyes @app is the new standard, it combines both field and handler definition and clears both storages before setting the new values. If you are adapting old code the quickest way is to replace the old @reactive statement with the respective @vars statement and to define handlers separately by @handlers, which then does not clear the REACTIVE_STORAGE, e.g. from

@reactive! mutable struct TreeDemo <: ReactiveModel
    d::R{Dict{String, Any}} = deepcopy(testdict)
    tree::R{Vector{Dict{Symbol, Any}}} = [dict_tree(testdict)]

    tree_selected::R{String} = ""
    tree_ticked::R{Vector{String}} = String[]
    tree_expanded::R{Vector{String}} = String[]
end

function handlers(model)
    on(model.isready) do isready
        isready && push!(model)
    end

    model
end

to

@appname TreeDemo

@vars begin
    d = deepcopy(testdict)
    tree = [dict_tree(testdict)]

    tree_selected = ""
    tree_ticked = String[]
    tree_expanded = String[]
end

@handlers
    onchange isready begin
        isready && @push
    end
end

hhaensel avatar Feb 16 '23 12:02 hhaensel

@hhaensel did you make any change about this? Are variables non-reactive by default now?

PGimenez avatar Mar 17 '23 15:03 PGimenez