-
Notifications
You must be signed in to change notification settings - Fork 482
HTTP request lifecycle
code.org
=> (DNS managed by route 53) => 54.192.37.35
(...etc...)
(dig code.org
=> 54.192.37.35
, whois 54.192.37.35
output shows it's an Amazon-owned IP, AMAZO-CF2
== CloudFront.)
Other "front door" domain names to code.org served by our main web application (pegasus & dashboard):
- studio.code.org
- advocacy.code.org
- hourofcode.com
- codeprojects.org
All of the above domain names are configured in Route53 to resolve to the IP addresses of CloudFront Distributions.
Each CloudFront Distribution has multiple Origins configured. The most important Origin typically is a DNS name that resolves to an AWS Application Load Balancer (ELBv2).
CloudFront => Elastic Load Balancing [ELB]
ELB => => multiple Frontend servers (Elastic Compute Cloud [EC2] with Auto Scaling)
Varnish Cache (port 80
) => port 8080
(dashboard) or port 8081
(pegasus) (depending on Host
header: code.org
=> pegasus
, studio.code.org
=> dashboard
)
This ERB logic generates VCL that decides whether to route an HTTP request to dashboard or pegasus.
Note that the Ruby HTTPCache
class generates a hash that is used to generate CloudFront Behaviors, Varnish VCL, and Rack middleware logic that all implement the same HTTP routing/cache rules for different types of environments.
NGiNX (port 808{0,1}
) => Unix socket/s (/run/unicorn/{dashboard,pegasus}.sock
)
Unicorn (UNIX socket/s) => Ruby application Rack server/s
Rack server definition files:
- dashboard:
dashboard/config.ru
- pegasus:
pegasus/config.ru
Pegasus web-application (/pegasus
- code.org)
Web-application based on sinatra
routing framework, with custom template and view-rendering layer.
-
pegasus/router.rb
: -class Documents < Sinatra::Base
- Additional routes are in
pegasus/routes/*.rb
, which are all recursively inserted into theDocuments
class.
- Additional routes are in
-
get_head_or_post '*'
-path
==/
for root page request -
resolve_document(uri)
->resolve_template('public', extnames, uri)
- resolves a URI to a path on the filesystem ending in/public
. A Sinatrabefore
hook sets a directory to search based on theHost
of the request prepended withsites.v3
. (e.g.:GET /
with headerHost: code.org
ultimately resolves topegasus/sites.v3/code.org/public/index.haml
on the filesystem.) -
document path
- read path from filesystem and render output -
render_ content, extname
- render content from template based on file extension -
after do
(Sinatraafter
hook) - load and renderlayouts/
andthemes/
templates from file:- layouts and themes 'wrap' themselves around the existing rendered body through the line:
body render_template(template, @locals.merge({body: body.join('')}))
, which calls#body
, which first reads (passed as a local variable to#render_template
) and then updates the template-rendered result.
- layouts and themes 'wrap' themselves around the existing rendered body through the line:
Dashboard application (/dashboard
- studio.code.org)
Standard Rails application.
-
dashboard/config/routes.rb
(runrails routes
for fullly-rendered route map) - Uses standard Rails routing and layouts/rendering (see Ruby on Rails Guides for full documentation, e.g., "Routing" and "Layouts and Rendering")
We have several Rack middlewarespec modules that are inserted into both Pegasus (via config.ru
) and Dashboard (via application.rb
), and provide 'shared' functionality to both web-applications. Some of these middleware apps are their own self-contained Sinatra apps (e.g., FilesApi
) that handle their defined routesexample when inserted into the middleware 'stack' for each web-app.