HTTP.jl
HTTP.jl copied to clipboard
Ctrl+C does not immediately stop the server in Julia 1.8
Hey! Because of https://github.com/JuliaLang/julia/issues/46635, pressing Ctrl+C
in the terminal no longer interrupts HTTP.listen
in Julia 1.8, you need to hold down Ctrl+C
to force a SIGINT.
https://user-images.githubusercontent.com/6933510/191505065-cdc0b986-d08b-4767-a280-e02df5c6cd09.mov
There are workarounds, either a simple one or a more advanced one that reads the tty stdin for a Ctrl+C
keypress. Should we include this in HTTP.jl?
I commented on https://github.com/JuliaLang/julia/issues/46635; I don't think it's reasonable to introduce a bunch of REPL/Terminals stdin processing just so we can interrupt a server.
yes I confirm this problem. Very painful indeed :(
@quinnj This is an important usability problem. If it's inappropriate to include directly, is there a way a hook can be registered that would let applications provide this logic?
I don't think a hook would be needed. I think you could do:
try
HTTP.serve(...)
catch e
if e isa InterruptException
# do stuff for ctrl + c
end
rethrow()
end
@quinnj thanks. Will try this
@quinnj That code snippet no longer works, like I demonstrated in my OP, right?
@fonsp is this what you are suggesting?
using HTTP, Sockets
todos = """
ToDo 1: check musks' tweet 😂
ToDo 2: feed dog 🐶
ToDo 3: sleep for atleast 8 hrs 🛌
"""
const HOST = ip"127.0.0.1"
const PORT = 9999
const ROUTER = HTTP.Router()
HTTP.register!(ROUTER, "GET", "/", req -> HTTP.Response(200, "Hello"))
HTTP.register!(ROUTER, "GET", "/list_todos", req -> HTTP.Response(200, todos))
@info "Server running, press Ctrl+C to interrupt..."
try
server = HTTP.serve!(ROUTER, HOST, PORT)
while Base.isopen(server)
sleep(.1)
end
catch e
@info "Closing server..."
close(server)
wait(server)
end
Yep!
I don't understand why InterruptException
doesn't work here. Seems fine in other cases. @quinnj were you able to figure it out? This is readline
from stdin
ERROR: InterruptException:
Stacktrace:
[1] poptask(W::Base.InvasiveLinkedListSynchronized{Task})
@ Base ./task.jl:921
[2] wait()
@ Base ./task.jl:930
[3] wait(c::Base.GenericCondition{Base.Threads.SpinLock})
@ Base ./condition.jl:124
[4] wait_readnb(x::Base.TTY, nb::Int64)
@ Base ./stream.jl:416
[5] eof(s::Base.TTY)
@ Base ./stream.jl:106
[6] iterate(itr::Base.EachLine{Base.TTY}, state::Nothing)
@ Base ./io.jl:1062
[7] top-level scope
@ ./REPL[29]:3
I haven't had a chance to look into this; last I did, I was told this was a change in Base and that it would take some massive effort to get the previous behavior back in HTTP.jl. I'll try to look into it again, but I still don't fully understand what changed in Base and why.