Serve static assets with an efficient cache policy - Nuxt.js + GAE - google-app-engine

I get the following from Lighthouse:
How do I change the Cache TTL on a Nuxt.js SSR website? I found some answers but nothing about Nuxt.js...
IMPORTANT: Deployed in Google App Engine

The specific answer for GAE Apps, is the parameter handlers.expiration in app.yaml file:
handlers:
- url: /_nuxt
static_dir: .nuxt/dist/client
expiration: 4d 5h
secure: always
Or if you want to configure it globally, set the default_expiration parameter at the root level:
default_expiration: 4d 5h
Allows d (days), h (hours), m (minutes) and s (seconds). Here's the docs

You can serve your static folder with custom cache policy following the render configuration.
As an example:
render: {
// Setting up cache for 'static' directory - a year in milliseconds
// https://web.dev/uses-long-cache-ttl
static: {
maxAge: 60 * 60 * 24 * 365 * 1000,
},
},

In addition to the answer, please note that - at the time of writing - the minimum time required by Lighthouse to pass is > 96.5d (Source : https://github.com/GoogleChrome/lighthouse/issues/11380)
I've followed the answer by #lmfresneda and managed to get the solution to work, making the cache time 30d : I still had the Lighthouse test fail until I changed it to "97d".

Related

AppEngine Flexible instances constantly respawning

I am deploying a Go application using AppEngine flexible. Below is my app.yaml. Sometimes after I deploy it stabilizes at 1 instance (it's a very low load application), but most of the time it constantly respawns upwards of 6 instances. My logs are filled with messages showing the new instances being created. There is nearly zero load on this application, why is AppEngine flexible constantly destroying and respawning instances?
Log showing constant respawning:
app.yaml
runtime: go
api_version: go1
env: flex
handlers:
- url: /.*
script: _go_app
health_check:
enable_health_check: True
check_interval_sec: 10
timeout_sec: 4
unhealthy_threshold: 2
healthy_threshold: 2
automatic_scaling:
min_num_instances: 1
max_num_instances: 10
cool_down_period_sec: 120 # default value
cpu_utilization:
target_utilization: 0.5
The problem was with my health check function. It originally looked like this:
func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
return
}
I then discovered this sentence in the documentation on how instances are managed:
You can write your own custom health-checking code. It should reply to /_ah/health requests with a HTTP status code 200. The response must include a message body, however, the value of the body is ignored (it can be empty).
So I changed the health check function to write a simple "ok" in response:
func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ok"))
return
}
The instances now behave according to my autoscale settings! The respawning is gone.
I obviously should have read the documentation closer, but there was zero indication of a problem in the health check logs. All health checks looked like they were passing. Hopefully this info is helpful to others.

Environment variables specified on app.yaml but it's not fetching on main.go

I've specified my environment variables in app.yaml and it's being fetched when I'm running it on my local machine but once I have it deployed - it's not fetching it.
Here's how I've set it up:
application: some-application
version: 1
runtime: go
api_version: go1
threadsafe: true
handlers:
- url: /.*
script: main.go
secure: always
env_variables:
ENVIRONMENT_VAR1: 'some key'
ENVIRONMENT_VAR2: 'some key'
ENVIRONMENT_VAR3: 'some key'
And I'm using os.Getenv("ENVIRONMENT_VAR1") to retrieve the key and it works when I run it on my local but fails to work when deployed on google app engine.
It is undocumented in the official doc: Defining environment variables, but environment variables defined in app.yaml in production are not set before init() functions are called. They are only set before serving the first request.
This issue was reported here. Quoting an AppEngine engineer's answer:
Right. Due to the nature of the implementation, environment variables are not available in your init functions, unfortunately.
Although they are not tied to requests, they are not set until after all the init functions have already run, but are set before the first request is handled.
As a result, you could use a sync.DoOnce in your main handler to perform any actions required based on the value of an environment variable since it will be properly set by that time.
Example of achieving this with Once.Do():
var once = sync.Once{}
func MainHandler(w http.ResponseWriter, r *http.Request) {
once.Do(mysetup)
// do your regular stuff here
}
func mysetup() {
// This function is executed only once. Read / use env vars here.
var1 := os.Getenv("ENVIRONMENT_VAR1")
_ = var1 // use var1
}
The answer icza provided worked for me. In addition, I put the once.Do() call in a handler for the /_ah/start method so that it would be called immediately when GAE started up my application.

WebPageTest complaining about not caching static resources even though I have caching enabled

I am testing my website on webpagetest.org. It gives me a
and then goes on to give this list:
Leverage browser caching of static assets: 63/100
WARNING - (2.0 hours) - http://stats.g.doubleclick.net/dc.js
WARNING - (5.5 days) - http://www.bookmine.net/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
WARNING - (5.5 days) - http://www.bookmine.net/favicon.ico
WARNING - (5.5 days) - http://www.bookmine.net/js/index.min.js
WARNING - (5.5 days) - http://www.bookmine.net/js/jquery-ui-1.8.13.custom.min.js
WARNING - (5.5 days) - http://www.bookmine.net/css/index.css
WARNING - (5.5 days) - http://www.bookmine.net/js/jquery.form.min.js
WARNING - (5.5 days) - http://www.bookmine.net/css/jquery-ui-1.8.13.custom.css
funny thing is that it does recognize I have caching enabled (set to 5.5 days as reported above), then what is it complaining about? I have also verified I have a default_expiration: "5d 12h" set in my app.yaml and from this link:
default_expiration
Optional. The length of time a static file served by a static file
handler ought to be cached by web proxies and browsers, if the handler
does not specify its own expiration. The value is a string of numbers
and units, separated by spaces, where units can be d for days, h
for hours, m for minutes, and s for seconds. For example, "4d 5h"
sets cache expiration to 4 days and 5 hours after the file is first
requested. If omitted, the production server sets the expiration to 10
minutes.
For example:
application: myapp version: alpha-001 runtime: python27 api_version: 1
threadsafe: true
default_expiration: "4d 5h"
handlers:
Important: The expiration time will be sent in the Cache-Control and Expires HTTP response headers, and therefore, the files are likely
to be cached by the user's browser, as well as intermediate caching
proxy servers such as Internet Service Providers. Once a file is
transmitted with a given expiration time, there is generally no way to
clear it out of intermediate caches, even if the user clears their own
browser cache. Re-deploying a new version of the app will not reset
any caches. Therefore, if you ever plan to modify a static file, it
should have a short (less than one hour) expiration time. In most
cases, the default 10-minute expiration time is appropriate.
I even verified response my website is returning in fiddler:
HTTP/200 responses are cacheable by default, unless Expires, Pragma,
or Cache-Control headers are present and forbid caching. HTTP/1.0
Expires Header is present: Sat, 26 Sep 2015 08:14:56 GMT
HTTP/1.1 Cache-Control Header is present: public, max-age=475200
public: This response MAY be cached by any cache. max-age: This
resource will expire in 132 hours. [475200 sec]
HTTP/1.1 ETAG Header is present: "74YGeg"
So why am I getting a D?
Adding some useful links:
- http://www.learningtechnicalstuff.com/2011/01/static-resources-and-cache-busting-on.html
- http://www.codeproject.com/Articles/203288/Automatic-JS-CSS-versioning-to-update-browser-cach
- https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#invalidating-and-updating-cached-responses
- https://developers.google.com/speed/docs/insights/LeverageBrowserCaching
- https://stackoverflow.com/a/7671705/147530
- http://www.particletree.com/notebook/automatically-version-your-css-and-javascript-files/
WebPagetest gives a warning if the cache expiration is set for less than 30 days. You can view that detail by clicking on the "D" grade in your test results and viewing the glossary for "Cache Static". You can also find that info here.
If you need to modify a cached static javascript file, you can add version number to the file path or in a querystring.

link that includess .php? in google app engine

I use app.yaml on google's app engine.
I have a link in my php file which is of this format: profile.php?id=1, which gives me the profile page for user 1. Any idea how to deal with this link in my app.yaml file? This is what I have done:
application: myappl-testing-858585
version: 1
runtime: php
api_version: 1
threadsafe: yes
handlers:
- url: /profile.php?id=
script: profile.php?id=
Your app.yaml file should only route the paths, like this:
handlers:
- url: /profile
script: profile.php
(Note that I also removed ".php" from the URL, since you really should not expose the internal file format like ".php", ".html", ".jsp", ".asp", etc. in your URLS... this is an implementation detail of your site, and it's both not good to bother users with it -- it makes for uglier URLs -- and it also makes it more difficult for you to modify your site in the future should you replace one implementation with another).
Then, in your *.php file, you simply use $_GET to test for the existence of / retrieve the ID.
In terms of your site structure, though, you may wish to consider changing the ID to a part of the path rather than a GET parameter if it is always a required parameter (just for URL nicety). In that case, you would register the handler like the following:
handlers:
- url: /profile/(\d+)
script: profile.php
... so that your URLs looked like "/profile/123" instead of "/profile?id=123".

dev_appserver: where do static routes get routed?

Could anyone point to roughly where in the python sdk code static routes get loaded into or accessed by http_server. This is to debug a failure to load static images. In eclipse I can see the static routes loading into var appinfo from the yaml file, and later can see the dynamic routes being checked during a request, but having trouble following the in-between steps.
Thanks
Update 11/30
Previously tried variations on the yaml, path, etc that were suggested in some docs and postings.
Here is one of them. In this case there is no 404 error, but image doesn't load and Firebug reports "Failed to the load the given URL".
app.yaml
application: crazywidget2
version: 1
runtime: python27
api_version: 1
threadsafe: false
handlers:
- url: /images
static_dir: /images
secure: always
-url: /.*
script: crazywidget2.py
secure: always
libraries:
- name: jinja2
version: latest
index.html
...
<img src="/images/xyz.gif" alt="XYZ illustration" />
...
crazywidget2.py
...
class MainPage(webapp2.RequestHandler):
def get(self):
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render({}))
...
...
app = webapp2.WSGIApplication([('/script_send', ScriptSend),
('/resetkey', ResetKey),
('/admin', Admin),
('/start', Start),
('/', MainPage)],
debug=True)
def main():
app.run()
if __name__=='__main__':
main()
Update 12/3
Turns out that in the above case it works if the static_dir is relative, "images" instead of "/images". In the absolute case it tries to open that path as is. Maybe some other variations would work as well.
Here are three relevant code pointers (all in google/appengine/tools/dev_appserver.py):
class FileDispatcher
CreateURLMatcherFromMaps()
DevAppServerRequestHandler._Dispatch()
I would assume though, there are easier ways to debug your problem. If you would post your app.yaml and the path you access and the response you get, people here could start to help you.
Just a hunch: does it work if you add a slash to the end of /images in your handlers? Try replacing /images with /images/ in both places that you use it in app.yaml.

Resources