gradio-app / gradio

Build and share delightful machine learning apps, all in Python. 🌟 Star to support our work!
http://www.gradio.app
Apache License 2.0
33.41k stars 2.52k forks source link

`demo.close()` doesn't release the port if it is not 7860 #3675

Closed oobabooga closed 1 year ago

oobabooga commented 1 year ago

Describe the bug

If I initialize a a gr.Blocks() interface with a custom server_port, the port is not released after demo.close().

Is there an existing issue for this?

Reproduction

  1. Launch the script below.
  2. Access the web UI in http://127.0.0.1:9441/?__theme=dark
  3. Click on "Apply and restart the interface"
  4. An error about port 9441 already being in use will appear in the terminal
import time

import gradio as gr

title ='Text generation web UI'
need_restart = False

def set_interface_arguments():
    global need_restart
    need_restart = True
    return

def create_interface():
    with gr.Blocks(analytics_enabled=False) as interface:
        reset_interface = gr.Button("Apply and restart the interface", type="primary")

        reset_interface.click(set_interface_arguments, None, None)
        reset_interface.click(lambda : None, None, None, _js='() => {document.body.innerHTML=\'<h1 style="font-family:monospace;margin-top:20%;color:lightgray;text-align:center;">Reloading...</h1>\'; setTimeout(function(){location.reload()},2500); return []}')

    # Launch the interface
    interface.queue()
    interface.launch(prevent_thread_lock=True, server_name='0.0.0.0', server_port=9441)

    return interface

interface = create_interface()

while True:
    time.sleep(0.5)
    if need_restart:
        need_restart = False
        interface.close()
        interface = create_interface()

Screenshot

No response

Logs

Closing server running on port: 9441
/home/me/miniconda3/lib/python3.10/site-packages/gradio/deprecation.py:40: UserWarning: The 'type' parameter has been deprecated. Use the Number component instead.
  warnings.warn(value)
Traceback (most recent call last):
  File "/home/me/miniconda3/lib/python3.10/site-packages/gradio/networking.py", line 119, in start_server
    s.bind((LOCALHOST_NAME, server_port))
OSError: [Errno 98] Address already in use

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/tmp/test.py", line 33, in <module>
    interface = create_interface()
  File "/tmp/test.py", line 22, in create_interface
    interface.launch(prevent_thread_lock=True, server_name='0.0.0.0', server_port=9441)
  File "/home/me/miniconda3/lib/python3.10/site-packages/gradio/blocks.py", line 1454, in launch
    server_name, server_port, local_url, app, server = networking.start_server(
  File "/home/me/miniconda3/lib/python3.10/site-packages/gradio/networking.py", line 122, in start_server
    raise OSError(
OSError: Port 9441 is in use. If a gradio.Blocks is running on the port, you can close() it or gradio.close_all().

System Info

`gradio==3.23.0`

Severity

annoying

space-nuko commented 1 year ago

I can't repoduce this on the latest main (I use windows), it may be platform specific

oobabooga commented 1 year ago

That's possible. The problem happens to me on Linux.

tensiondriven commented 1 year ago

I reproduce this on ubuntu frequently. When the app I'm using (text-generation-webui) sometimes crashes, if I attempt to restart it, I get an error:

Loading settings from settings.json...
Loading llama-30b-4bit-128g...
Loading model ...
Done.
Loaded the model in 7.33 seconds.
Loading the extension "gallery"... Ok.
/home/j/miniconda3/lib/python3.10/site-packages/gradio/deprecation.py:40: UserWarning: The 'type' parameter has been deprecated. Use the Number component instead.
  warnings.warn(value)
Traceback (most recent call last):
  File "/home/j/miniconda3/lib/python3.10/site-packages/gradio/networking.py", line 119, in start_server
    s.bind((LOCALHOST_NAME, server_port))
OSError: [Errno 98] Address already in use

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/mnt/local/machine-learning-proxmox/apps/textgen-latest/server.py", line 458, in <module>
    create_interface()
  File "/mnt/local/machine-learning-proxmox/apps/textgen-latest/server.py", line 454, in create_interface
    shared.gradio['interface'].launch(prevent_thread_lock=True, share=shared.args.share, server_name='0.0.0.0', server_port=shared.args.listen_port, inbrowser=shared.args.auto_launch)
  File "/home/j/miniconda3/lib/python3.10/site-packages/gradio/blocks.py", line 1381, in launch
    server_name, server_port, local_url, app, server = networking.start_server(
  File "/home/j/miniconda3/lib/python3.10/site-packages/gradio/networking.py", line 122, in start_server
    raise OSError(
OSError: Port 8003 is in use. If a gradio.Blocks is running on the port, you can close() it or gradio.close_all().

Is there some way that a consumer of Gradio can trap this and either manually free the port or ... something?

tensiondriven commented 1 year ago

@space-nuko if I can provide any additional debugging information, please let me know!

tensiondriven commented 1 year ago

@oobabooga Could this be related?

demo.launch(prevent_thread_lock=False, inbrowser=True)  # prevent main thread from exiting
liasece commented 1 year ago

Same problem. Even if I run fuser -k 7860/tcp & python launch.py --listen --port 7860, I still get this annoying error: OSError: Port 7860 is in use. If a gradio.Blocks is running on the port, you can close() it or gradio.close_all().

tensiondriven commented 1 year ago

It looks like invoking load() inside the Blocks context manager causes gradio to not release the port. I was able to repro in this branch of text-generation-webui on linux (ubuntu): https://github.com/tensiondriven/text-generation-webui/blob/graceful-shutdown-demo/server.py#L21

Note that the sleep() calls are necessary to give load() time to allocate memory or whatever; if you remove the sleeps and just open/close gradio quickly, it will work.

This might not be an easy thing to reproduce on your system since text-generation-webui has a bunch of language model dependencies.