Note: This is a cross post because I wasn't sure if this was a technical issue or a bug so the bug can be found here
A couple weeks ago I wrote up a prototype for adding a flexible environment service to our appengine project that is primarily standard environment services. The prototype was based on the java quickstart sample "HelloworldSpringBoot" with some minor modifications.
After my success with the prototype I moved over to a more production set of code for this service, developed it for a couple weeks and attempted to deploy on Jan 12th, 4 days ago. The app refused to start and after several attempts at simplifying the app to just a single route I could not get the app to start.
I switch back to the prototype code, deployed to the original project that code was working in and am seeing the same behavior where the app is not starting.
There is no one error message to point to so I have a couple that I'll list here that may be the culprit.
The first is the most obvious, but may be a generic catch-all:
Exception in thread "main" java.lang.IllegalStateException: No Available Context
at com.google.cloud.runtimes.jetty9.DeploymentCheck.lifeCycleStarted(DeploymentCheck.java:46)
at org.eclipse.jetty.util.component.AbstractLifeCycle.setStarted(AbstractLifeCycle.java:179)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:69)
at org.eclipse.jetty.xml.XmlConfiguration$1.run(XmlConfiguration.java:1511)
at org.eclipse.jetty.xml.XmlConfiguration$1.run(XmlConfiguration.java:1438)
at java.security.AccessController.doPrivileged(Native Method)
at org.eclipse.jetty.xml.XmlConfiguration.main(XmlConfiguration.java:1437)
The next happens much earlier in the startup, but seems benign:
javax.servlet.ServletException: Not running on Jetty, JSR-356 support unavailable at org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer.onStartup(WebSocketServerContainerInitializer.java:193) at org.eclipse.jetty.plus.annotation.ContainerInitializer.callStartup(ContainerInitializer.java:140) at org.eclipse.jetty.annotations.ServletContainerInitializersStarter.doStart(ServletContainerInitializersStarter.java:63) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:329) at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1501) at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1463) at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:785) at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:261) at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:545) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at org.eclipse.jetty.deploy.bindings.StandardStarter.processBinding(StandardStarter.java:41) at org.eclipse.jetty.deploy.AppLifeCycle.runBindings(AppLifeCycle.java:188) at org.eclipse.jetty.deploy.DeploymentManager.requestAppGoal(DeploymentManager.java:502) at org.eclipse.jetty.deploy.DeploymentManager.addApp(DeploymentManager.java:150) at org.eclipse.jetty.deploy.providers.ScanningAppProvider.fileAdded(ScanningAppProvider.java:180) at org.eclipse.jetty.deploy.providers.WebAppProvider.fileAdded(WebAppProvider.java:447) at org.eclipse.jetty.deploy.providers.ScanningAppProvider$1.fileAdded(ScanningAppProvider.java:64) at org.eclipse.jetty.util.Scanner.reportAddition(Scanner.java:610) at org.eclipse.jetty.util.Scanner.reportDifferences(Scanner.java:529) at org.eclipse.jetty.util.Scanner.scan(Scanner.java:392) at org.eclipse.jetty.util.Scanner.doStart(Scanner.java:313) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at org.eclipse.jetty.deploy.providers.ScanningAppProvider.doStart(ScanningAppProvider.java:150) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at org.eclipse.jetty.deploy.DeploymentManager.startAppProvider(DeploymentManager.java:564) at org.eclipse.jetty.deploy.DeploymentManager.doStart(DeploymentManager.java:239) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:131) at org.eclipse.jetty.server.Server.start(Server.java:452) at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:113) at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:113) at org.eclipse.jetty.server.Server.doStart(Server.java:419) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at org.eclipse.jetty.xml.XmlConfiguration$1.run(XmlConfiguration.java:1511) at org.eclipse.jetty.xml.XmlConfiguration$1.run(XmlConfiguration.java:1438) at java.security.AccessController.doPrivileged(Native Method) at org.eclipse.jetty.xml.XmlConfiguration.main(XmlConfiguration.java:1437)
Then there is this guy that happens just after the previous:
org.eclipse.jetty.webapp.WebAppContext: Failed startup of context o.e.j.w.WebAppContext@7e0b0338{/,file:///var/lib/jetty/webapps/root/,UNAVAILABLE}{/root.war}
Also, here are the pertinent files:
app.yaml:
runtime: java
env: flex
runtime_config: # Optional
jdk: openjdk8
service: service2
handlers:
- url: /.*
script: this field is required, but ignored
manual_scaling:
instances: 1
build.gradle:
buildscript { // Configuration for building
ext {
springBootVersion = '1.5.9.RELEASE'
}
repositories {
jcenter() // Bintray's repository - a fast Maven Central mirror & more
mavenCentral()
maven { url 'https://repo.spring.io/libs-snapshot' }
}
dependencies {
classpath 'com.google.cloud.tools:appengine-gradle-plugin:+'
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
}
}
repositories { // repositories for JARs you access in your code
maven {
url 'https://maven-central.storage.googleapis.com' // Google's mirror of Maven Central
}
maven {
url "http://repo.spring.io/libs-snapshot"
}
jcenter()
mavenCentral()
}
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'com.google.cloud.tools.appengine'
apply plugin: 'org.springframework.boot'
dependencies {
// Add your dependencies here.
compile "org.springframework.boot:spring-boot-starter-web", { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat' }
compile (
"org.springframework.boot:spring-boot-starter-actuator",
"org.springframework.boot:spring-boot-starter-jetty"
)
testCompile (
"org.springframework.boot:spring-boot-starter-test:$springBootVersion"
)
}
appengine {
deploy { // deploy configuration
stopPreviousVersion = true // default - stop the current version
promote = true // default - & make this the current version
}
}
group = 'com.example' // Generated output GroupId
version = '1.0-SNAPSHOT' // Version in generated output
sourceCompatibility = 1.8
targetCompatibility = 1.8
HelloworldApplication.java:
package com.example.java.gettingstarted;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class HelloworldApplication {
@RequestMapping("/service2/")
public String home() {
return "Helloooooooo Nurse!";
}
/**
* (Optional) App Engine health check endpoint mapping.
* @see <a href="https://cloud.google.com/appengine/docs/flexible/java/how-instances-are-managed#health_checking"></a>
* If your app does not handle health checks, a HTTP 404 response is interpreted
* as a successful reply.
*/
@RequestMapping("/_ah/health")
public String healthy() {
// Message body required though ignored
return "Still surviving.";
}
public static void main(String[] args) {
SpringApplication.run(HelloworldApplication.class, args);
}
}
I'm also running gcloud version 184.0.0
The solution ended up being a little bit magical, but the SpringBoot documentation was telling once the appengine standard documentation pointed me in the right direction.
We were deploying a war and locally it was running with the embedded container. After setting jetty as provided and adding the magical SpringBootServletInitializer to the root, things started working. I don't know why this was not needed two weeks ago, but it is definitely needed now.
Placing this file at the root did the trick.
Thanks for the help.