Environment sharing between request threads in Google App Engine

Viewed 209

I have noticed that when I create a new thread using the request thread factory provided by GAE then the new thread has the same Environment as the parent thread. (The identityHashCode of the current environment is the same in both threads.)

On the one hand, this is nice because the newly created thread starts with the same context as the parent. The problem is that the Environment is not immutable. It contains the ".currentNamespace" attribute which is used in namespace handling. If one of the threads changes the current namespace it is applied on all threads which is clearly not what I want.

My idea to fix this was that I created an own Environment implementation and when a new thread is created I copy the content of the current environment into this new environment and set this environment as current on the new thread. So the new thread starts with the same context but it can independently change later.

This solution worked during initial testing but then I run into a problem

Caused by: java.lang.ClassCastException: MyEnvironmentImplementation cannot be cast to com.google.apphosting.runtime.ApiProxyImpl$EnvironmentImpl
    at com.google.apphosting.runtime.ApiProxyImpl.log(ApiProxyImpl.java:67)

I have no access to the code of com.google.apphosting.runtime.ApiProxyImpl but it is clear that this method tries to cast the interface it received into its own implementation class without checking the type.

I find this strange because there is a void setEnvironmentFactory(ApiProxy.EnvironmentFactory factory) in the ApiProxy so it is expected that someone might use a different implementation of the Environment interface than the default one.

Is there another way to use different namespaces in different request threads?
Is this unchecked casting considered a bug or is it fundamentally wrong to use my own Environment implementation?

I use app engine standard with 1.9.84 of the java sdk.

Edit: It is actually documented that "This should not be used from user-code." on the ApiProxy.setEnvironmentForCurrentThread() and ApiProxy.setEnvironmentFactory() methods. So my suggested workaround is not expected to work. You shouldn't try something like it either.

1 Answers

No need to use Google API threads. Do not let Google API's cause you problems. Do this yourself outside of the browser as I describe here.

Write a program that sub-classes your browser, and subclass each window that is opened. Then run a javascript on each page that saves your result to the location bar where it is easy to collect it later. Then collect that information from the location bar and then put the previous (which was in the location bar) back into it so that it will be seen as being the same as it was before.

If you want to use that data in a different web page then put it there via your separate program.

Each opened browser window could theoretically be running a separate google api process.

With your program subclassing all of the browser windows separately, have your program to share information between them without the google api getting confused.

Like this:

Write a program (in VB6 sp5 I did this years ago. Never use any later version of Visual Studio for anything. In C++11 this should work.).

Using FireFox as a browser for this example.

(1) Have your program start and Subclass FireFox.

(2) Have your program tell Firefox to open up a new window (might need to make this a FireFox "new tab" or maybe not).

(3) Tell your program to get the pre-handle of the newly opening window. Do this quickly and keep trying (up to 30 seconds if you have an overloaded operating system) until you get the pre-handle, then assign a new Window's handle to that new window or new tab.

(4) Use that new handle and send a javascript to the address bar (minus the "j"), meaning that you send an entire "avascript..." to that address bar, then add the previous "j" since if FireFox detects that you placed any command into the addressbar with the entire word "javascript" it will stop you from doing some things (if I recall correctly).

(5) Run that javascript obtaining from or placing into each page your changes.

(6) The web pages in the browser, having the javascript running in them do part of the work.

(7) No need to use Google API threads.

Related