The sanic.app run parameter has not been checked for port type, which results in an error when setting the workers parameter because the port is a string type

I found a problem. When using the run method in sanic.app, if workers are not specified in the parameter (that is, when the default workers value is used), the port parameter can be an integer or a string to start the service, but when workers When it exceeds 2, if the port parameter is a string, the following error will be reported. I looked at the source code and found that if the workers exceed 2, the bottom layer will call the serve_multiple method, and the python sock.bind((host, port)) method will be used internally, but the port will be restricted to an integer here. It is hoped that when the service is started, the port can be restricted to ensure that the problem will not be reported to the downstream.

Version:
python:3.8.7
sanic:21.6.2 / 20.12.2
OS:centos 7.4

Example:
from sanic import Sanic

from sanic.response import json

app = Sanic(“My Hello, world app”)

@app.route(’/’)

async def test(request):

return json({'hello': 'world'})

if name == ‘main’:

# Service started successfully

h = "127.0.0.1"

p = "8888"

app.run(host=h, port=p, debug=True, access_log=True, auto_reload=False)

# Service started successfully

h = "127.0.0.1"

p = 8888

app.run(host=h, port=p, debug=True, access_log=True, auto_reload=False)

# Service started successfully

h = "127.0.0.1"

p = 8888

w = 4

app.run(host=h, port=p, debug=True, access_log=True, workers=w, auto_reload=False)

# Service failed to start

h = "127.0.0.1"

p = "8888"

workers = 4

app.run(host=h, port=p, debug=True, access_log=True, workers=w, auto_reload=False)

Error is

Traceback (most recent call last):
  File "apps/ft/ft_run.py", line 18, in <module>
    ft_main_app.run(debug=True, access_log=True, host=host, port=port, workers=workers, auto_reload=False)
  File "/usr/local/python3/lib/python3.8/site-packages/sanic/app.py", line 1113, in run
    serve_multiple(server_settings, workers)
  File "/usr/local/python3/lib/python3.8/site-packages/sanic/server.py", line 1069, in serve_multiple
    sock = bind_socket(
  File "/usr/local/python3/lib/python3.8/site-packages/sanic/server.py", line 987, in bind_socket
    sock.bind((host, port))
TypeError: an integer is required (got type str)

Do you have a code snippet? What is an example app.run(...) that you are referring to?

Also OS and Sanic version, since it looks like python is 3.8

from sanic import Sanic

from sanic.response import json

app = Sanic("My Hello, world app")

@app.route('/')

async def test(request):

    return json({'hello': 'world'})

if __name__ == '__main__':

    # Service started successfully

    h = "127.0.0.1"

    p = "8888"

    app.run(host=h, port=p, debug=True, access_log=True, auto_reload=False)

    # Service started successfully

    h = "127.0.0.1"

    p = 8888

    app.run(host=h, port=p, debug=True, access_log=True, auto_reload=False)

    # Service started successfully

    h = "127.0.0.1"

    p = 8888

    w = 4

    app.run(host=h, port=p, debug=True, access_log=True, workers=w, auto_reload=False)

    # Service failed to start

    h = "127.0.0.1"

    p = "8888"

    workers = 4

    app.run(host=h, port=p, debug=True, access_log=True, workers=w, auto_reload=False)

Version:
python:3.8.7
sanic:21.6.2 / 20.12.2
OS:centos 7.4

Example:

from sanic import Sanic

from sanic.response import json

app = Sanic("My Hello, world app")

@app.route('/')

async def test(request):

    return json({'hello': 'world'})

if __name__ == '__main__':

    # Service started successfully

    h = "127.0.0.1"

    p = "8888"

    app.run(host=h, port=p, debug=True, access_log=True, auto_reload=False)

    # Service started successfully

    h = "127.0.0.1"

    p = 8888

    app.run(host=h, port=p, debug=True, access_log=True, auto_reload=False)

    # Service started successfully

    h = "127.0.0.1"

    p = 8888

    w = 4

    app.run(host=h, port=p, debug=True, access_log=True, workers=w, auto_reload=False)

    # Service failed to start

    h = "127.0.0.1"

    p = "8888"

    workers = 4

    app.run(host=h, port=p, debug=True, access_log=True, workers=w, auto_reload=False)

@qiuyue I’ll be honest, I am not super motivated to making the change. The fact that it works as a str with a single worker is a somewhat happy accident. Certainly not intentional, and is more a factor of the underlying Python create_server than anything that Sanic is intentionally doing. With that said, if you feel strongly about this, I am happy to entertain a PR

That either converts it here:

Or perhaps even better, here:


If you do, please make sure to add a unit test to confirm the use case:

  1. app.run w/ port as int and workers=1
  2. app.run w/ port as int and workers=2
  3. app.run w/ port as str and workers=1
  4. app.run w/ port as str and workers=2