Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add website.run() method #441

Closed
techtonik opened this issue Jun 18, 2015 · 30 comments · Fixed by #445
Closed

Add website.run() method #441

techtonik opened this issue Jun 18, 2015 · 30 comments · Fixed by #445

Comments

@techtonik
Copy link
Contributor

To avoid writing this for every app:

#!/usr/bin/env python
"""
The main script to start website for development,
which also exports WSGI application for production.
"""

from aspen.website import Website

# by WSGI convention, we need to create webapp object
# and by default most WSGI servers look for 'application'
application = Website([])

if __name__ == '__main__':
    from wsgiref.simple_server import make_server
    make_server('', 8000, application).serve_forever()

Do that:

#!/usr/bin/env python
"""
The main script to start website for development,
which also exports WSGI application for production.
"""
from aspen.website import Website

# by WSGI convention, we need to create webapp object
# and by default most WSGI servers look for 'application'
application = Website([])

if __name__ == '__main__':
    application.run()
@chadwhitacre
Copy link
Contributor

Sure, but let's call it rundev to make it clear that it's not for production usage.

@techtonik
Copy link
Contributor Author

Why it is not suitable for production? I don't see why it can not be used for small sites.

@chadwhitacre
Copy link
Contributor

Well, you said it yourself in the docstring:

The main script to start website for development,
which also exports WSGI application for production.

@techtonik
Copy link
Contributor Author

Yes, but it is because Gratipay uses deployment through a Heroku defined process. I don't know which server do they prefer and why.

@chadwhitacre
Copy link
Contributor

I don't see why it can not be used for small sites.
I don't know which server do they prefer and why.

The limitation with wsgiref.make_server is that it can only handle one request at a time. If you receive a request that takes one second to fulfill (maybe it does a lot with the database, or it's receiving a big upload), then the website won't be able to serve any other requests during that second. For production, this is acceptable for only hobby or otherwise very-low-traffic applications. How about application.run_with_hobby_server() or run_with_toy_server?

@techtonik
Copy link
Contributor Author

How about application.run_with_hobby_server() or run_with_toy_server?

Not a chance that I will remember those. Note that Flask provides app.run() method, but it uses more capable WSGI framework as dependency - werzeugh or something. Ok, let it be rundev().

@chadwhitacre
Copy link
Contributor

it uses more capable WSGI framework as dependency - werzeugh or something

werkzeug.serving is also single-threaded and single-process.

rundev

I don't like that website.foo confuses the role of the server with the role of the WSGI application. I would rather see foo(website), like this:

from aspen import publish, Website

website = Website()

if __name__ == '__main__':
    publish(website)

(P.S. Flask doesn't use application. I'm not sure we need to, either)

@techtonik
Copy link
Contributor Author

werkzeug.serving is also single-threaded and single-process.

Then I see no reasons not to have .run() for convenience. If people would like to optimize the site for performance, they will use appropriate server like gunicorn etc. I thinks that's became pretty obvious in Python world, but could be explained once more in docstring.

I don't like that website.foo confuses the role of the server with the role of the WSGI application.

I also don't like that Website inherits from Configuration instead of encapsulating it.

publish(website)

For me publishing means compile and upload, or release draft to public.

(P.S. Flask doesn't use application. I'm not sure we need to, either)

It names it app, but it is WSGI application.
https://github.com/mitsuhiko/flask/blob/master/flask/app.py#L771

@pjz
Copy link
Contributor

pjz commented Jun 18, 2015

I vote no Website.run() because it moves WSGI-server code into the main core. Python -m aspen is convenient enough.

@chadwhitacre
Copy link
Contributor

I thinks that's became pretty obvious in Python world

Yeah, I can see that.

I also don't like that Website inherits from Configuration instead of encapsulating it.

I agree, but that's a separate issue: reticketed as #444 and added to the roadmap (#357).

I vote no Website.run() because it moves WSGI-server code into the main core. Python -m aspen is convenient enough.

Too late. We already have WSGI-server code in the main core.

For me publishing means compile and upload, or release draft to public.

Here it means "put it on the network." I chose publish over mount. How about just serve?

from aspen import serve, Website

website = Website()

if __name__ == '__main__':
    serve(website)

It names it app, but it is WSGI application.

Right. Website instances are also WSGI applications. ;-)

chadwhitacre added a commit that referenced this issue Jun 18, 2015
Makes the quickstart quicker; closes #441.
@pjz
Copy link
Contributor

pjz commented Jun 18, 2015

C'mon, we did this already - down this path lies engines and etc. __main__ is the only WSGI server code we have in the app, and it's just as a convenience. It's where it won't bother anyone who doesn't use it (unlike if it's on the main Website object).

@chadwhitacre
Copy link
Contributor

@pjz Check my implementation in #445. It's not on the main Website object.

@chadwhitacre
Copy link
Contributor

@pjz And against "down this path lies engines and etc.," consider the example of Flask and Django. They both provide this convenience, and as @techtonik suggests: "I thinks that's became pretty obvious in Python world [that this is not a high-performance server], but could be explained once more in docstring."

@pjz
Copy link
Contributor

pjz commented Jun 18, 2015

alright fine. As soon as it passes tests.

@chadwhitacre
Copy link
Contributor

Done, though because of #446 I dropped back to:

from aspen import serve, website

website = website.Website()

if __name__ == '__main__':
    serve(website)

@pjz pjz closed this as completed in #445 Jun 18, 2015
@techtonik
Copy link
Contributor Author

@whit537 note that website = website.Website() is not a valid WSGI app anymore.

@chadwhitacre
Copy link
Contributor

note that website = website.Website() is not a valid WSGI app anymore.

Why not?

@techtonik
Copy link
Contributor Author

Because by default webservers look for application name.

@pjz
Copy link
Contributor

pjz commented Jun 19, 2015

what webservers? Link to docs, please.

@techtonik
Copy link
Contributor Author

Note that mod_wsgi requires that the WSGI application entry point be called 'application'. If you want to call it something else then you would need to configure mod_wsgi explicitly to use the other name.

https://code.google.com/p/modwsgi/wiki/QuickConfigurationGuide#WSGI_Application_Script_File

@techtonik
Copy link
Contributor Author

As you can see, it is composed of a single Python function. It is called “application” as this is default function that the uWSGI Python loader will search for (but you can obviously customize it).

https://uwsgi-docs.readthedocs.org/en/latest/WSGIquickstart.html#the-first-wsgi-application

@techtonik
Copy link
Contributor Author

Gunicorn will look for a WSGI callable named application if not specified.

https://gunicorn-docs.readthedocs.org/en/latest/run.html#django

@techtonik
Copy link
Contributor Author

Need more? =)

@chadwhitacre
Copy link
Contributor

website = website.Website() is not a valid WSGI app anymore,
Because by default webservers look for application name.

@techtonik Bound variable name is a bad test for the validity of a WSGI application, because all three of the servers you cite will, in fact, have no problem using a Website instance bound to a website variable as a WSGI application, because each has a simple mechanism for specifying a WSGI app named something other than application. In any case, the matter is irrelevant for Aspen, because you're free to bind your Website instance to whatever variable name you like: that's a nice side-benefit of the fact that Aspen is a library.

@chadwhitacre
Copy link
Contributor

In any case, the matter is irrelevant for Aspen [...]

Actually, the one place it's relevant is in aspen.wsgi ... #449.

@techtonik
Copy link
Contributor Author

each has a simple mechanism for specifying a WSGI app named something other than application

Not sure about the simple. At least in mod_wsgi it doesn't seem simple.

@techtonik
Copy link
Contributor Author

Actually, the one place it's relevant is in aspen.wsgi ... #449.

Ok. Didn't know that aspen.wsgi exists.

@chadwhitacre
Copy link
Contributor

Didn't know that aspen.wsgi exists.

Sounds like someone hasn't read the fine 📖, nor used a 🔍 engine. ;-)

@chadwhitacre
Copy link
Contributor

Easing mod_wsgi configuration reticketed as #452, based on the search results I just looked at. :-)

@techtonik
Copy link
Contributor Author

Well, at first I was thinking that aspen is just a simplates engine like Jinja2. So I didn't think it requires to be a WSGI app. And after all that problem was deep in the stack of the bugs I was trying to unwind, and in this situation the ADD just becomes worse. =)

Changaco pushed a commit that referenced this issue Mar 11, 2016
Makes the quickstart quicker; closes #441.
Changaco pushed a commit that referenced this issue Mar 11, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants