diff --git a/src/webserver/WebServer.jl b/src/webserver/WebServer.jl index a016fcadad..911a325704 100644 --- a/src/webserver/WebServer.jl +++ b/src/webserver/WebServer.jl @@ -103,12 +103,43 @@ function port_serversocket(hostIP::Sockets.IPAddr, favourite_port, port_hint) return port, serversocket end +struct RunningPlutoServer + http_server + initial_registry_update_task::Task +end + +function Base.close(ssc::RunningPlutoServer) + close(ssc.http_server) + wait(ssc.http_server) + wait(ssc.initial_registry_update_task) +end + +function Base.wait(ssc::RunningPlutoServer) + try + # create blocking call and switch the scheduler back to the server task, so that interrupts land there + while isopen(ssc.http_server) + sleep(.1) + end + catch e + println() + println() + Base.close(ssc) + (e isa InterruptException) || rethrow(e) + end + + nothing +end + """ run(session::ServerSession) Specifiy the [`Pluto.ServerSession`](@ref) to run the web server on, which includes the configuration. Passing a session as argument allows you to start the web server with some notebooks already running. See [`SessionActions`](@ref) to learn more about manipulating a `ServerSession`. """ function run(session::ServerSession) + Base.wait(run!(session)) +end + +function run!(session::ServerSession) if is_first_run[] is_first_run[] = false @info "Loading..." @@ -293,21 +324,7 @@ function run(session::ServerSession) will_update && println(" Updating registry done ✓") end - try - # create blocking call and switch the scheduler back to the server task, so that interrupts land there - while isopen(server) - sleep(.1) - end - catch e - println() - println() - close(server) - wait(server) - wait(initial_registry_update_task) - (e isa InterruptException) || rethrow(e) - end - - nothing + return RunningPlutoServer(server, initial_registry_update_task) end precompile(run, (ServerSession, HTTP.Handlers.Router{Symbol("##001")})) diff --git a/test/Configuration.jl b/test/Configuration.jl index 0507f688ea..4d2d6c2f54 100644 --- a/test/Configuration.jl +++ b/test/Configuration.jl @@ -64,8 +64,7 @@ end host = 🍭.options.server.host secret = 🍭.secret println("Launching test server...") - server_task = @async Pluto.run(🍭) - sleep(2) + server = Pluto.run!(🍭) local_url(suffix) = "http://$host:$port/$suffix" withsecret(url) = occursin('?', url) ? "$url&secret=$secret" : "$url?secret=$secret" @@ -123,7 +122,7 @@ end @test requeststatus(url, method) ∈ 200:399 # 3xx are redirects end - @async schedule(server_task, InterruptException(); error=true) + close(server) end @testset "disable mimetype via workspace_custom_startup_expr" begin diff --git a/test/webserver.jl b/test/webserver.jl index 0d94e1887c..009ff34631 100644 --- a/test/webserver.jl +++ b/test/webserver.jl @@ -32,25 +32,21 @@ using Pluto.WorkspaceManager: WorkspaceManager, poll base_url, ) 🍭 = Pluto.ServerSession(; options) - server_task = @async Pluto.run(🍭) + server = Pluto.run!(🍭) - # FYI, you should normally use a PlutoEvent for things we do in this test instead of polling! Don't use this as an example. - @test poll(10) do - server_running() - end + @test server_running() - sleep(20) - @test HTTP.get("http://$host:$port/edit"; status_exception=false).status == 404 + sleep(3) + @test poll(20) do + # should not exist because of the base url setting + HTTP.get("http://$host:$port/edit"; status_exception=false).status == 404 + end for notebook in values(🍭.notebooks) SessionActions.shutdown(🍭, notebook; keep_in_session=false) end - schedule(server_task, InterruptException(); error=true) - - # wait for the server task to finish - # normally this `wait` would rethrow the above InterruptException, but Pluto.run should catch for InterruptExceptions and not bubble them up. - wait(server_task) + close(server) end @testset "Exports" begin @@ -69,14 +65,16 @@ end # without notebook at startup - options = Pluto.Configuration.from_flat_kwargs(; port, launch_browser=false, workspace_use_distributed=true, require_secret_for_access=false, require_secret_for_open_links=false) + options = Pluto.Configuration.from_flat_kwargs(; + port, launch_browser=false, + workspace_use_distributed=true, + require_secret_for_access=false, + require_secret_for_open_links=false + ) 🍭 = Pluto.ServerSession(; options) - server_task = @async Pluto.run(🍭) + server = Pluto.run!(🍭) - # FYI, you should normally use a PlutoEvent for things we do in this test instead of polling! Don't use this as an example. - @test poll(10) do - server_running() - end + @test server_running() @test isempty(🍭.notebooks) @@ -112,10 +110,7 @@ end SessionActions.shutdown(🍭, notebook; keep_in_session=false) end - schedule(server_task, InterruptException(); error=true) - # wait for the server task to finish - # normally this `wait` would rethrow the above InterruptException, but Pluto.run should catch for InterruptExceptions and not bubble them up. - wait(server_task) + close(server) end end # testset