add run_server(server) convenience func
the run() function contains valuable logic for kicking off the StatReloader and the Multiprocess workers, however it does not give you access to the server instance before starting and subsequently blocking. thus splitting out the server start logic into a function accepting an already initialized server instance solves this problem.
I'll add tests/docs for this once it's generally accepted as a good idea
@rmorshea Why would you want to have access to the Server object?
@Kludex I'm running the server in a thread and want to block the parent thread until Server.started is True - examples from https://github.com/encode/uvicorn/issues/742 suggest sub-classing Server to accomplish this, but that feels overly complicated for something that ought to be relatively simple.
In fact this comment suggests a relatively similar change. In that case the create_runner() function returns a Server instance rather than accepting an already initialized one (as mine proposes) but the principle is the same.
@Kludex @florimondmanca @euri10 I would personally recommend this PR over #1248... simple & elegant, plus it was written first! Just needs to resolve conflicts from master and add "run_server" to __all__ in uvicorn/__init__.py.
I'd be happy to make the requisite changes once the choice is made to go with this PR over the other.
Thanks for the PR @rmorshea . Sorry for taking so long to act here! 😞
I'm going to follow this idea on #1248.
@Kludex IMO this PR is better than the other one which has a bunch of issues (hence the multitude of comments)... why not close that one instead? See, e.g., https://github.com/encode/uvicorn/pull/1248#discussion_r757809716
I'm not happy about having multiple ways to run uvicorn in code e.g. run and run_server.
I'm also not that convinced about #1248 either fwiw. 😅
In any case, if you want, feel free to open a discussion, and propose the alternatives. I don't think a discussion presenting the possibilities, and why we should do this was created in a good way to convince others about this (or similar).
@Kludex both PRs introduce run_server() fyi. The main reason I see being the ability to control the creation of your config/server before running, which Server.run() almossstttt does except it ignores the config's reload options.
(Food for thought/alternative: rather than adding yet another function, could just stuff the reload logic in Server.run() so that we can simply do create_server_however_i_want(create_config_however_i_want()).run()).
@Kludex both PRs introduce run_server() fyi.
Oh... True. I didn't see that, sorry.
But after checking it again, the PRs are pretty similar anyway.
@Kludex yep, quite similar, hence why I'd suggest re-opening this one and closing the other:
- in-so-far as they are similar, this one was written first (basic PR etiquette to use the original PR rather than a copycat PR)
- in-so-far as they are different, this one is better