Is App engine ThreadManager still usable? - google-app-engine

I'm using GAE standard environment.
When calling
ThreadManager.createBackgroundThread({
try {
doSomething()
} catch (exception: Exception) {
//do nothing - logging failed
}
})
I got the error:
java.lang.IllegalStateException: This feature is only available to backend instances.
I'm using the new services (modules?), as the backend instances are documented as deprecated. So are there any methods that allows to mark an instance as a backend one?

well, you need to define the scaling type for your module. here you can find an overview
https://cloud.google.com/appengine/docs/standard/python/an-overview-of-app-engine
Please try to configure manual or basic scaling for your module. Only for this scaling types background thread are allowed

Related

How to configure a GCP App Engine properly

I am struggling to understand the difference and benefits of a few terms which I use while I setup my App Engine instance:
I am wondering how does server handle more than one request? Does it need to create a new instance of my server code for every request, sounds unlikely but I want to clarify. OR does it create a copy of my function handling the request? A typical function of mine looks like the following:
app.get("/", limiter, async function(req , res){
try {
my code
} catch (err){
console.log(err);
res.status(400).send('Something went wrong')
}
})
What is the relation of a flex environment vs standard environment?
When does a new instance is required?
My app.yaml looks like the following:
runtime: nodejs12
env: standard
manual_scaling:
instances: 1 // Is this a bad idea in production?
resources:
cpu: 1
memory_gb: 0.5
disk_size_gb: 10
Please I need help in understanding this so I can setup my instance properly.
Neither a new server nor a new function instance is needed. Instead, the same function (async function(req , res) in your case) is called several times concurrently. Each call will have a separate request and response instance (req and res in your case).
Standard and Flexible are two different App Engine offerings from Google with different features and different pricing. Standard is more dynamic (quicker start-up, quicker deployment, scales down to 0 instances). Flexible offers more options (any programming language, support for web sockets etc.). For more details, see Choosing an App Engine environment
.
Unless you explicitly specify the number of instances, Google App Engine monitors request latency and probably CPU load and will increase and decrease the number of running instances depending on the actual load (possibly within the limits you have set). If a single instance is sufficient to handle the load of your application, you can fix the instance count at 1. That's a valid setting.

How to patch env_variable using REST API in App Engine Standard?

Lately I've been deploying apps on App Engine Standard and sometimes I accidentally deploy a version with a typo in my env_variables specified on app.yaml. Let's say that I don't want to deploy a new version because it takes time and this typo should be easily fixed with a "quick patch".
I followed the GAE Admin REST API doc and played around with the API Explorer. It turns out that the request body accepts envVariables so I was thinking that this API can solve my problem but for some reason it fails.
Error:
{
"error": {
"code": 400,
"message": "This operation is only supported on the following field(s): [automatic_scaling.cool_down_period_sec, automatic_scaling.cpu_utilization.target_utilization, automatic_scaling.max_idle_instances, automatic_scaling.max_total_instances, automatic_scaling.min_idle_instances, automatic_scaling.min_total_instances, automatic_scaling.standard_scheduler_settings.max_instances, automatic_scaling.standard_scheduler_settings.min_instances, automatic_scaling.standard_scheduler_settings.target_cpu_utilization, automatic_scaling.standard_scheduler_settings.target_throughput_utilization, instance_class, manual_scaling.instances, serving_status]",
"status": "INVALID_ARGUMENT"
}
}
Request Parameters:
appsId: PROJECT_ID
servicesId: SERVICE_NAME
versionsId: 2021xxxxx
updateMask: envVariables
Request Body:
{
"envVariables": {
"my_key":"my_value"
}
}
Overall question: Is it not possible to patch env_variables on App Engine Standard using REST API or I'm just missing something? Are there any alternatives to avoid redeployment?
Nope, there is no other alternative for this particular use case.
The reason you cannot modify the envVariables using GAE Rest API is that those variables are used when your app is being built in App Engine, so modifying them will imply re-build all the app which implies at the same time you need to redeploy the app.
You can modify the scaling settings since those not depend on the application or how it is built.
Now, that you're able to see envVariables as an option in the API explorer does not mean it is intended to be used with apps.services.versions.patch, in fact that option is shown as well with others just like a generic menu with all the possible options in the API but in the documentation you share it is not mentioned you can use it for the particular method you mention.

What is the correct context for appengine taskqueue in go112 standard runtime

I cannot get the appengine taskqueue to accept any context I throw at it:
import (
"context"
"google.golang.org/appengine"
"google.golang.org/appengine/taskqueue"
)
/* snip */
ctx:= context.Background()
task := taskqueue.NewPOSTTask("/b/mytask", params)
_, err = taskqueue.Add(ctx, task, "")
if err != nil {
return fmt.Errorf("adding background task with path %s: %v", task.Path, err)
}
I'm calling appengine.Main() in my main.go main func as stated by the go111 migration docs (But this line is missing in go112 migration docs so I'm not sure it's required).
I've tried:
context.Background()
request.Context()
appengine.NewContext(r)
appengine.BackgroundContext()
context.TODO()
All result in error:
not an App Engine context
except for appengine.BackgroundContext() which gets:
service bridge HTTP failed: Post
http://appengine.googleapis.internal:10001/rpc_http: dial tcp
169.254.169.253:10001: i/o timeout
I experienced the same problems when migrating a GAE standard project from go19 to go112 in order to use go modules. In addition I got a lot of "502 bad gateway" messages.
Replacing http.ListenAndServe() in main() with appengine.Main() fixed the context problem. Moving to go111 instead of 112 took care of the other issue. The docs and examples are not very clear on this.
The documentation for migration to 1.12 states:
Use Cloud Tasks to enqueue tasks from Go 1.12 using the cloudtasks package. You can use any App Engine service as the target of an App Engine task.
But the cloudtasks package documentation (as at today’s date) is clearly marked as beta and unstable. So the answer here is probably. This feature is unsupported.
That said, I’m using it in production under go111 without any serious issue that I have noticed so far.
You're seeing internal.flushLog: Flush RPC: service bridge HTTP failed because you have appengine.Main() or other appengine lib calls while trying to run a Go 1.12+ runtime. (My guess is that the older runtime had to call into some Google-internal accounting infrastructure and that's not available for the 1.12 "next gen" systems.)
The solution isn't to downgrade your Go versions -- you're missing a ton of performance and security improvements doing that, and you can't take advantage of the new hardware -- the solution is to remove all the calls to the appengine lib and use GCP's cloud libraries instead (see https://godoc.org/cloud.google.com/go)

detect AppEngine vs basic server

I am developing a web app to run on either Google's AppEngine or a basic server with file storage (it may not stay that way but that's the current status).
How do I detect whether the AppEngine services (most importantly blobstore) are available at runtime?
I have tried using code like the following:
try{
Class.forName( "com.google.appengine.api.blobstore.BlobstoreServiceFactory" );
logger.info( "Using GAE blobstore backend" );
return new GAEBlobService();
}catch( ClassNotFoundException e ){
logger.info( "Using filesystem-based backend" );
return new FileBlobService();
}
but it doesn't work because BlobstoreServiceFactory is available at compile time. What fails if trying to use GAE's blobstore without a GAE server is the following:
com.google.apphosting.api.ApiProxy$CallNotFoundException: The API package 'blobstore' or call 'CreateUploadURL()' was not found.
There's a few things you can use.
You can check the runtime environment to check the running version of App Engine. Check the section about "The Environment" in the runtime docs: https://developers.google.com/appengine/docs/java/runtime
You could also do what you were doing, and attempt to make an call that uses the SDK API functions (instead of just checking for the existence of a class) and catch the exception. This may negatively impact performance since you're making an extra RPC.
You could check request headers for GAE specific request headers too.

Is it thread-safe to store data inside a static field when deploying on Google App Engine?

I was browsing through the code of Vosao CMS, an open source CMS hosted on Google App Engine (which I think is an awesome idea), and I stumbled upon the following code inside the CurrentUser class:
/**
* Current user session value cache class. Due to GAE single-threaded nature
* we can cache currently logged in user in static property. Which we set in
* authentication filter.
*/
public class CurrentUser {
private static UserEntity user;
public static UserEntity getInstance2() {
return user;
}
public static void setInstance2(UserEntity aUser) {
user = aUser;
}
}
I've never used GAE, but this sounds really weird to me.
Is GAE really "single threaded"? Is it safe to store request-scoped data inside a static field when using GAE?
Does this mean that, for each JVM instance, only one HTTP request will be executed at a time, while all the other requests are waiting?
Is this a common GAE idiom? If not, what would be the best GAE idiom to store such an UserEntity for the duration of a request? Shouldn't one use a ThreadLocal here, like they do in Spring Security? Or some kind of scoped bean (managed by the Dependency Injection container)?
Is GAE really "single threaded"? Is it safe to store request-scoped data inside a static field when using GAE?
It used to be that way (until 1.4.3) and it still is by default.
Now, you can specify that your app is threadsafe, and then you will receive concurrent requests to the same JVM/servlet.
Does this mean that, for each JVM instance, only one HTTP request will be executed at a time, while all the other requests are waiting?
For other request, you would probably get another JVM. But that is outside of your control. They can also just wait.
Currently, the Java and Python runtimes on App Engine are both single threaded; you're correct that this means only one HTTP request will be executed per JVM, but multiple JVMs will be started simultaneously to handle multiple incoming requests.
This could change at any time in the future, however - the Java Servlet spec permits multi-threading. As a result, you should definitely use a ThreadLocal.

Resources