Init and destroy function - google-app-engine

I am still beginner with golang in Google Cloud Appengine (standard).
I want to use a function that is automatically call for the instance shutting down.
There is a function init called during startup.
Now I am looking for the opposite part like a destroy function.
Seems there is something like that for python, but could not find
anything for golang.
How could you realise such a destroy fuction in google appengine instances ?

This is documented at Go - How Instances are Managed.
Unfortunately the Go doc is incomplete, here's the link to the Pyton version: Python - How Instances are Managed. The way it is implemented / supported is language-agnostic.
When an instance is spin up, an HTTP GET request is sent to the /_ah/start path.
Before an instance is taken down, an HTTP GET request is sent to the /_ah/stop path.
You should use package init() functions for initialization purposes as that always runs, and only once. If a request is required for your init functions, then register a handler to the _/ah/start path.
And you may register a handler to /_ah/stop and implement "shutdown" functionality like this:
func init() {
http.HandleFunc("/_ah/stop", shutdownHandler)
}
func shutdownHandler(w http.ResponseWriter, r *http.Request) {
doSomeWork()
saveState()
}
But you can't rely on this 100%:
Note: It's important to recognize that the shutdown hook is not always able to run before an instance terminates. In rare cases, an outage can occur that prevents App Engine from providing 30 seconds of shutdown time. Thus, we recommend periodically checkpointing the state of your instance and using it primarily as an in-memory cache rather than a reliable data store.

Related

Detecting "loading request" in Google App Engine Python

I need to make sure some code is initialized on a GAE instance when it is spun up. Is there a way to detect in the code that the request is a "loading request"?
I tried adding the initialization code to my warmup handler but it does not seem that warmup is guaranteed to be called. I also tried giving each service in my application a single idle instance to increase the chance of warmup being called.
Note: this answer is written with the python 2.7 standard environment in mind, I'm not sure if something equivalent would be possible for all other languages/runtimes and how it'd work.
Indeed, the warm-up requests, if configured, are only effective if there is already at least one instance running for the service, which isn't always the case.
You could place the desired init code in the main service file which declares your service's app - that code is only executed when the service app is initialized, which happens exactly once per instance lifetime, regardless of the request being a loading or a warm-up one.
Something along these lines:
import ...
def my_desired_init_function():
pass # replace with what you need to do
my_desired_init_function()
app = webapp2.WSGIApplication(...)

How to warm up app engine endpoint

I have appengine endpoint and trying to reduce latency on few first calls to newly created endpoint instance. Application is written in Java and endpoints are auto scaled.
To address this issue I configured idle instance, although even if instance is already created, first few calls routed to it consume some extra time. Following documentation I've implemented the custom servlet handling warm up requests and marked the EndpointsServlet as load on startup.
Inside the warm up servlet I've put code that initiates some commonly used services, load some data etc. Effect was almost impossible to notice.
After it I have implemented calls to methods exposed by the endpoint like that:
call("/_ah/api/teamly/v1/test/dummy")
It works for some cases (even most of them) and after calling few key methods instance is really ready to serve. The problem I'm facing now is that if I'm using auto scaling for some module I can't route the request to specific instance.
So the question is:
How should I properly warm up the endpoint instance to avoid load requests initiated from frontend.
You need to put a listener to /_ah/warmup and then make calls to any resources you want it to be warmed up. You can find detailed information at:
Configuring Warmup Requests to Improve Performance

Initializing Go AppEngine app with Cloud Datastore

in init() function for GAE's golang app, how can I set-up initial values for my application ?
How to read from Cloud Datastore in the init() function or immediately after applications start-up ? As I understand, server cannot write to the local filesystem and Cloud Datastore is the only option ?
I need some global variables and slices of data..
Using static files
On AppEngine you don't have access to the file system of the host operating system, but you can access files of your web application (you have read-only permission, you can't change them and you can't create new files in the app's folder).
So the question is: can your application's code change the data that you want to read and use for initialization? Or is it fine if it is deployed "statically" with your app's code?
If you don't need to change it (or only when you redeploy your app), easiest is to store it as a "static" file as part of your webapp. You may refer to files of your app using relative paths, where the current or working directory is your app's root. E.g. if your app contains a data folder in its root (where app.yaml resides), and there is an init_values.txt file inside the data folder, you can refer to it with the path: data/init_values.txt.
One important note: not every file is readable by code, this depends on the app configuration. Quoting from Configuring with app.yaml / Static file handlers:
If you have data files that need to be read by the application code, the data files must be application files, and must not be matched by a static file pattern.
Using the Datastore
You can't use AppEngine services that require a Context outside of handlers (because the creation of a Context requires an *http.Request value). This by nature means you can't use them in package init() functions either.
Note that you can use them from cron jobs and tasks added to task queues, because tasks and cron jobs are executed by issuing HTTP GET requests.
You have to restructure your code so that your initialization (e.g. reading from the Datastore) gets called from a handler.
Example of achieving this with Once.Do():
var once = sync.Once{}
func MainHandler(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r)
once.Do(func() { mysetup(ctx) })
// do your regular stuff here
}
func mysetup(ctx appengine.Context) {
// This function is executed only once.
// Read from Datastore and initialize your vars here.
}
"Utilizing" warmup requests
Yes, this may cause first requests to take considerably longer to serve. For this purpose (to avoid this) I recommend you to utilize Warmup requests. A warmup request is issued to a new instance before it goes "live", before it starts serving user requests. In your app.yaml config file you can enable warmup requests by adding -warmup to the inbound_services directive:
inbound_services:
- warmup
This will cause the App Engine infrastructure to first issue a GET request to /_ah/warmup. You can register a handler to this URL and perform initialization tasks. As with any other request, you will have an http.Request in the warmup handler.
But please note that:
..you may encounter loading requests, even if warmup requests are enabled in your app.
Which means that in rare cases it may happen a new instance will not receive a warmup request, so its best to check initialization state in user handlers too.
Related questions:
How do I store the private key of my server in google app engine?
Fetching a URL From the init() func in Go on AppEngine
Environment variables specified on app.yaml but it's not fetching on main.go

GAE behavior when relocating an application to another server

Two questions:
Does Google App Engine send any kind of message to an application just before relocating it to another server?
If so, what is that message?
No it doesnt. It doesnt relocate either, old instances keep running (and eventually stop when idle for long enough) while new ones are spawned.
There are times when App Engine needs to move your instance to a different machine to improve load distribution.
When App Engine needs to turn down a manual scaling instance it first
notifies the instance. There are two ways to receive this
notification. First, the is_shutting_down() method from
google.appengine.api.runtime begins returning true. Second, if you
have registered a shutdown hook, it will be called. It's a good idea
to register a shutdown hook in your start request. After the
notification is issued, existing requests are given 30 seconds to
complete, and new requests immediately return 404.
If an instance is
handling a request, App Engine pauses the request and runs the
shutdown hook. If there is no active request, App Engine sends an
/_ah/stop request, which runs the shutdown hook. The /_ah/stop request
bypasses normal handling logic and cannot be handled by user code; its
sole purpose is to invoke the shutdown hook. If you raise an exception
in your shutdown hook while handling another request, it will bubble
up into the request, where you can catch it.
The following code sample demonstrates a basic shutdown hook:
from google.appengine.api import apiproxy_stub_map
from google.appengine.api import runtime
def my_shutdown_hook():
apiproxy_stub_map.apiproxy.CancelApiCalls()
save_state()
# May want to raise an exception
runtime.set_shutdown_hook(my_shutdown_hook)
Alternatively, the following sample demonstrates how to use the is_shutting_down() method:
while more_work_to_do and not runtime.is_shutting_down():
do_some_work()
save_state()
More details here: https://developers.google.com/appengine/docs/python/modules/#Python_Instance_states

How could I manage the App Engine Go runtime context to avoid App Engine lock-in?

I'm writing a Go application to run on App Engine's Go runtime.
I notice that pretty much any operation which uses an App Engine service (such as Datastore, Mail, or even Capabilities) requires that you pass it an instance of appengine.Context which must be retrieved using the function appengine.NewContext(req *http.Request) Context.
While I am writing this app for App Engine, I want to be able to move it to some other platform (possibly one which doesn't support any of the App Engine API) easily and quickly if I should so choose.
So, I'm abstracting away the actual interaction with App Engine services and API's by writing little wrappers around any App-Engine-specific interaction (including request handling functions). With this approach, if I ever do wish to move to a different platform, I'll just rewrite those specific modules which tie my application to App Engine. Easy and straightforward.
The only problem is that appengine.Context object. I can't pass it down from my request handlers through my layers of logic to the modules which handle these API's without tying pretty much all of my code to App Engine. I could pass the http.Request object from which the appengine.Context object can be derived, but that would require coupling things that probably shouldn't be coupled. (I think it's best practice for none of my application to even know it's a web application except those portions specifically dedicated to handling HTTP requests.)
The first solution that sprang to mind was to just create a persistent variable in some module. Something like this:
package context
import (
"appengine"
)
var Context appengine.Context
Then, in my request handlers, I can set that variable with context.Context = appengine.NewContext(r) and in the modules that directly use App Engine services, I can fetch the context by accesing context.Context. None of the intervening code would need to know of the appengine.Context object's existence. The only problem is that "multiple requests may be handled concurrently by a given instance", which can lead to race conditions and unexpected behavior with this plan. (One request sets it, another sets it, the first one accesses it and gets the wrong appengine.Context object.)
I could in theory store the appengine.Context to datastore, but then I'd have to pass some request-specific identifier down the logic layers to the service-specific modules identifying which appengine.Context object in datastore is the one for the current request, which would again couple things I don't think should be coupled. (And, it would increase my application's datastore usage.)
I could also pass the appengine.Context object down the whole logic chain with the type interface{} the whole way and have any module which doesn't need the appengine.Context object ignore it. That would avoid tying most of my application to anything specific. That also seems highly messy, however.
So, I'm at a bit of a loss how to cleanly ensure the App-Engine-specific modules which need the appengine.Context object can get it. Hopefully you folks can give me a solution I have yet to think of myself.
Thanks in advance!
This is tricky because your self-imposed scoping rule (which is a sensible one) means not passing a Context instance around, and there is nothing similar to Java's ThreadLocal to achieve the same ends by sneaky means. That's actually a Good Thing, really.
Context combines logging support (easy) with a Call to appengine services (not easy). There are I think ten appengine functions that need a Context. I can't see any clean solution other than wrapping all of these behind your own facade.
There is one thing that can help you - you can include a configuration file with your app that indicates whether it's in GAE or otherwise, using a flag of some sort. Your global boolean need only store this flag (not a shared context). Your facade functions can then consult this flag when deciding whether to use NewContext(r) to obtain the Context to access GAE services, or use a lookalike structure to access your own substitute services.
Edit: As a final remark, when you solve this may I invite you to share how you did it, possibly even with an open-source project? Cheeky of me to ask, but if you don't ask... ;-)
I (hopefully) solved this issue by wrapping my request handlers (in this example one called "realHandler") like this:
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ds := NewDataStore(r)
realHandler(w, r, ds)
})
NewDataStore creates a DataStore, which is a simple wrapper that abstracts the GAE datastore. It has an unexposed field where it stores the context:
type DataStore struct {
c appengine.Context
}
func NewDataStore(req *http.Request) *DataStore {
return &DataStore{appengine.NewContext(req)}
}
Within the request handler, I can just access the abstracted datastore when I need it without worrying about the GAE context, which has already been set:
func realHandler(w http.ResponseWriter, req *http.Request, db *DataStore) {
var s SomeStruct{}
key, err := db.Add("Structs", &s)
...
}
Particularly in case of Datastore you should be able to reuse the same appengine.Context among different requsts. I haven't tried to do it myself but that's the way an alternative API for Datastore called goon works:
Goon differs from the datastore package in various ways: it remembers the appengine Context, which need only be specified once at creation time
The fact that storage should depend on HTTP request sounds ridiculous by the way. I don't think Datastore depends on a particular request in the usual sense. Most probably, it's needed to identify a particular Google App Engine application which obviously stays the same from request to request. My speculations are based on quick skim over the source code of google.golang.org/appengine.
You may do similar observations in regard of the other Google App Engine APIs. Of cause all the details could be implementation specific and I'd performed more deep research before actually using those observations in a real application.
It's worth to note that Go team introduced a golang.org/x/net/context package.
Later on the context was made available in Managed VMs, the repo is here. The documentation states:
This repository supports the Go runtime on App Engine, including both classic App Engine and Managed VMs. It provides APIs for interacting with App Engine services. Its canonical import path is google.golang.org/appengine.
What it means is that you could easily write another packages out of dev environment depending on appengine.
In particular it becomes very easy to wrap around packages like appengine/log (trivial log wrapper example).
But even more important this allows one to create handlers in a form:
func CoolHandler(context.Context, http.ResponseWriter, *http.Request)
There's an article about a context package on Go blog here. I wrote about using context here. If you decide to use the handler with context passing around it's good to create context for all requrests in one place. You can do it by using non standard requrest router like github.com/orian/wctx.
I handled this by wrapping appengine.NewContext behind an interface, and provide different implementations through different packages. That way, I don't have to link GAE into any binaries where it isn't used:
type Context interface {
GetHTTPContext(r *http.Request) context.Context
}
I provide a method for subpackages to register themselves when imported for side effects, sort of database/sql-style:
var _context Context
func Register(c Context) {
_context = c // Nil checking, double registration checking omitted for brevity
}
I start with a default implementation for vanilla, non-GAE binaries, that simply grabs the existing context:
var _context Context = &defaultContext{} // use this by default
type defaultContext struct {}
func (d *defaultContext) GetHTTPContext(r *http.Request) context.Context {
return r.Context()
}
Then I put an App Engine implementation in a package mything/context/appengine:
import(
ctx "mything/context"
)
type aecontext struct {}
func (a *aecontext) GetHTTPContext(r *http.Request) context.Context {
return appengine.NewContext(r)
}
func init() {
ctx.Register(&aecontext{})
}
Then my GAE binary can pull in the subpackage, which registers itself in init:
import(
_ "mything/context/appengine"
)
And my app code uses GetHTTPContext(r) to get an appropriate context to pass into dependencies.

Resources