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

Ctrl+C does not immediately stop the server in Julia 1.8

Open fonsp opened this issue 2 years ago • 10 comments

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?

fonsp avatar Sep 21 '22 12:09 fonsp

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.

quinnj avatar Oct 08 '22 00:10 quinnj

yes I confirm this problem. Very painful indeed :(

AbhimanyuAryan avatar Nov 03 '22 02:11 AbhimanyuAryan

@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?

clarkevans avatar Nov 04 '22 14:11 clarkevans

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 avatar Nov 04 '22 15:11 quinnj

@quinnj thanks. Will try this

AbhimanyuAryan avatar Nov 04 '22 17:11 AbhimanyuAryan

@quinnj That code snippet no longer works, like I demonstrated in my OP, right?

fonsp avatar Nov 07 '22 13:11 fonsp

@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

AbhimanyuAryan avatar Nov 13 '22 13:11 AbhimanyuAryan

Yep!

fonsp avatar Nov 14 '22 13:11 fonsp

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

AbhimanyuAryan avatar Nov 20 '22 22:11 AbhimanyuAryan

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.

quinnj avatar Nov 29 '22 07:11 quinnj