Jetty не может запустить приложение весенней загрузки в appengine Flexible
Примечание. Это перекрестная публикация, поскольку я не был уверен, что это техническая проблема или ошибка, поэтому ее можно найти здесь.
Пару недель назад я написал прототип для добавления гибкого сервиса среды к нашему проекту appengine, который в основном является стандартным сервисом среды. Прототип был основан на образце быстрого запуска Java "HelloworldSpringBoot" с некоторыми незначительными изменениями.
После успеха с прототипом я перешел к более производительному набору кода для этого сервиса, разработал его за пару недель и попытался развернуть 12 января 4 дня назад. Приложение отказалось запускаться, и после нескольких попыток упростить приложение до единого маршрута я не смог запустить приложение.
Я переключаюсь обратно на прототип кода, развернут в исходном проекте, в котором работал код, и наблюдаю то же поведение, когда приложение не запускается.
Там нет ни одного сообщения об ошибке, чтобы указать, поэтому у меня есть пара, которую я перечислю здесь, которые могут быть виновником.
Первый является наиболее очевидным, но может быть универсальным:
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)
Следующее происходит намного раньше при запуске, но кажется доброкачественным:
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)
Тогда есть этот парень, который происходит сразу после предыдущего:
org.eclipse.jetty.webapp.WebAppContext: Failed startup of context o.e.j.w.WebAppContext@7e0b0338{/,file:///var/lib/jetty/webapps/root/,UNAVAILABLE}{/root.war}
Кроме того, вот соответствующие файлы:
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);
}
}
Я также использую версию gcloud 184.0.0
1 ответ
Решение оказалось немного волшебным, но документация SpringBoot рассказывала, как только стандартная документация устройства указала мне правильное направление.
Обратите внимание, что WebApplicationInitializer необходим только в том случае, если вы создаете файл war и внедряете его. Если вы предпочитаете запускать встроенный контейнер, тогда вам это вообще не понадобится.
Мы развертывали войну, и локально она шла со встроенным контейнером. После установки jetty, как предусмотрено, и добавления волшебного SpringBootServletInitializer в корень, все стало работать. Я не знаю, почему это не было нужно две недели назад, но это определенно необходимо сейчас.
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
System.out.println("ServletInitializer called.");
return application.sources(HelloworldApplication.class);
}
}
Размещение этого файла в корне сделал свое дело.
Спасибо за помощь.