Johann
Johann

Reputation: 29867

Debugging GAE microservices locally but without using localhost

I would like to debug my Google App Engine (GAE) app locally but without using localhost. Since my application is made up of microservices, the urls in a production environment would be along the lines of:

https://my-service.myapp.appspot.com/

But code in one service can call another service and that means that the urls are hardcoded. I could of course use a mechanism in code to determine whether the app is running locally or on GAE and use urls that are different although I don't see how a local url would handle the since the only way to run an app locally is to use localhost. Hence:

http://localhost:8080/some-service

Notice that "some-service" maps to a servlet, whereas "my-service" is a name assigned to a service when the app is uploaded. These are really two different things.

The only possible solution I was able to find was to use a reverse proxy which would map one url to a different one. Still, it isn't clear whether the GAE development SDK even supports this.

Upvotes: 0

Views: 441

Answers (2)

Johann
Johann

Reputation: 29867

This can be accomplished with the following steps:

  1. Create an entry in the hosts file
  2. Run the App Engine Dev server from a Terminal using certain options
  3. Use IntelliJ with Remote debugging to attach the App Engine Dev server.

    1. To edit the hosts file on a Mac, edit the file /etc/hosts and supply the domain that corresponds to your service:. Example:

127.0.0.1 my-service.myapp.com

After you save this, you need to restart your computer for the changes to take place.

  1. Run the App Engine Dev server manually:

dev_appserver.sh --address=0.0.0.0 --jvm_flag=-Xdebug --jvm_flag=-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 [path_to_exploded_war_directory]

  1. In IntelliJ, create a debug configuration. Use the Remote template to create this configuration. Set the host to the url you set in the hosts file and set the port to 8000.

You can set a breakpoint and run the app in IntelliJ. IntelliJ will attach to the running instance of App Engine Dev server.

Because you are using a port during debugging and no port is actually used when the app is uploaded to the GAE during production, you need to add code that identifies when the app is running locally and when it's running on GAE. This can be done as follows:

private String mServiceUrl = "my-service.my-app.appspot.com";
...
if (SystemProperty.environment.value() != SystemProperty.Environment.Value.Production) {
           mServiceUrl += ":8000";
}

See https://cloud.google.com/appengine/docs/standard/java/tools/using-local-server

An improved solution is to avoid including the port altogether and not having to use code to determine whether your app is running locally or on the production server. One way to do this is to use Charles (an application for monitoring and interacting with requests) and use a feature called Remote Mapping which lets you map one url to another. When enabled, you could map something like:

https://my-service.my-app.appspot.com/

to

https://localhost:8080

You would then enable the option to include the original host, so that this gets delivered to the local dev server. As far as your code is concerned it only sees:

https://my-service.my-app.appspot.com/

although the ip address will be 127.0.0.1:8080 when remote mapping is enabled. To use https on local host however does require that you enable ssl certificates for Charles.

For a complete overview on how to setup and debug microservices for a GAE Java app in IntelliJ, see:

https://github.com/JohannBlake/gae-microservices

Upvotes: 1

Dan Cornilescu
Dan Cornilescu

Reputation: 39814

Personally I chose to detect the local development vs GAE environment and build my inter-services URLs accordingly. I feel it was a well-worthy effort, I've been (re)using it a lot. No reverse proxy or any other additional ops necessary, it just works.

Granted, I'm using Python, so I'm not 100% sure a complete similar Java solution exists. But maybe it can point you in the right direction.

To build the per-service URLs I used modules.get_hostname() (the implementation is presented in Resolve Discovery path on App Engine Module). I believe the Java equivalent would be getInstanceHostname() from com.google.appengine.api.modules. This method, when executed on the local server, automatically provides the particular port the server listens to for each service.

BTW, all my services for an app are executed by a single development server process, which listens on multiple ports (this is, I guess, how it can provide the modules.get_hostname() info). See Running multiple services using dev_appserver.py on different ports. This is part I'm unsure about: if/how the java local dev server can simultaneously run multiple services. Apparently this used to be supported some time ago (when services were still called modules):

Upvotes: 1

Related Questions