Hot restart of the main loop when the source code changes

Hi, everybody!
I’m currently working on the Julia backend for Plotly Dash and I’m faced with the following task. In Python and R, Dash has the following feature: if the server is running in debug mode, changes to the app’s source code will restart the server. This way, you don’t need to press ctrl-C in the terminal after each change and restart the application.
I’m trying to implement this for Julia and the first my experiments gave this draft solution (spied on Python’s flask):

function test_hot_restart(main_loop::Function)
    if haskey(ENV, "SUBPROCESS")
        app_path = abspath(Base.PROGRAM_FILE)
        files = FileStat[]
        parse_includes(app_path, files) #parse files recursively with  Base.parse_input_line to find include Exprs
        
        @async main_loop()

        poll_until_changed(files) #Waiting for changes in any of the found files
        exit(3)
    else
        julia_str = joinpath(Sys.BINDIR, Base.julia_exename())
        new_env = deepcopy(ENV)
        new_env["SUBPROCESS"] = "1"
        cmd = Cmd(`$(julia_str) $(app_path)`, env = new_env, ignorestatus = true)
        while true
            p = run(cmd)
            p.exitcode != 3 && break
        end
    end
end

This solution seems to work, but perhaps someone can offer a more robust one?

P.S.
For a better understanding of the problem, the source file that I need to track for changes looks in the simplest case something like this:

using Dash, DashHtmlComponents
app = dash()
app.layout = html_div("test")
run_server(app; debug = true)

the main loop is started inside run_server (by HTTP.serve call). So I don’t see a way to use Revise.jl here. In addition, there is a requirement that the hot restart mode is enabled in runtime by the debug argument, and not by a macro or imported an extra package in user side.

1 Like

Hey @waralex, were you able to find a more robust solution here? I’m running up against a similar problem and was hoping to find a nice Revise based solution

Hi @caleb-allen!
Unfortunately, I didn’t find it :frowning: In Dash, it now works like this - it looks at all the included files and restarts the server when any of it change.

1 Like

In “FemotCleaner” (a bot that updates Julia code from 0.7 to 1.0) there was a Revise.revise() call in the main loop:

From what I recall, it worked pretty well, assuming the changes were Revise compatible.

2 Likes

@kristoffer.carlsson this is great! I’ve tried using Revise.revise() from within code, but I hadn’t thought to use Base.invokelatest. I’ll give this a shot!

@kristoffer.carlsson that did the trick! invokelatest was the key. Thanks for the suggestion!

1 Like