CTRL + C w/Spring Загрузка и Gradle Убивает Gradle Демон
Я использую плагин Spring Boot Gradle для запуска сервера Tomcat и моего приложения. Я запускаю сервер Tomcat через gradle bootRun
. Я также включил демон Gradle, надеясь сделать сборки Gradle быстрее.
Однако включение демона ничто. Каждый раз, когда я останавливаю сервер через Ctrl + C, снова запустите сервер с помощью gradle bootRun
, я получаю сообщение:
Starting a new Gradle Daemon for this build (subsequent builds will be faster).
Ctrl + C не только останавливает сервер Tomcat под обложками Spring Boot, но также убивает демона Gradle. Что поражает цель демонского режима Gradle.
Есть ли лучший способ остановить сервер, надеюсь, через интерфейс командной строки в том же терминале, для которого я начал tomcat с gradle bootRun
, который поддерживает демон Gradle?
Ответы
Ответ 1
Это все еще проблема в Gradle 4. Мой лучший компромисс/решение (построение ответа charlie_pl):
- Нажмите
ctrl+z
, чтобы отправить выполняемый процесс на задний план.
- Убейте процесс следующим образом:
kill $(ps aux | grep "MyApp" | grep -v grep | awk '{print $2}')
- Перезагрузка:
./gradlew run ...
Ответ 2
Я не знаком с плагином Spring, поэтому, по-видимому, нет команды "bootStop" (как есть в плагине Jetty). Кроме того, после расширенного поиска я не думаю, что для желаемого результата есть опция командной строки.
Одним из вариантов, хотя, по общему признанию, является kludge, является использование API-интерфейса Tooling. (Полный пример кода здесь.)
Идея состоит в том, чтобы запустить долговременную задачу в Groovy script. По команде script остановит задачу и вызовет gradle tasks
, чтобы щекотать демона.
Из связанного выше кода GitHub долговременная задача может быть:
task runService() << {
ant.delete(file: "runService.log")
def count = 0
while(true) {
new File("runService.log").withWriterAppend {
it.writeLine("[runService] count: ${count}")
}
println "sleeping ...."
try { Thread.sleep(5 * 1000) } catch (Exception ex) {}
count++
}
}
Идея Groovy script заключается в том, чтобы запустить задачу в фоновом потоке, а затем отправить маркер отмены после получения команды.
Для ясности я проиллюстрирую два раздела. Первый раздел - фоновый поток:
class BuildRunner implements Runnable {
def connector
def tokenSource
def taskName
BuildRunner(connector, tokenSource, taskName) {
this.connector = connector
this.tokenSource = tokenSource
this.taskName = taskName
}
public void run() {
def connection = connector.connect()
try {
def build = connection.newBuild()
build.withCancellationToken(tokenSource.token())
build.setStandardOutput(System.out)
build.setStandardError(System.err)
build.forTasks(taskName)
build.run()
println "${taskName} is finishing ..."
} catch(BuildCancelledException bcex) {
println "received cancel signal"
println "tickling daemon ..."
tickleDaemon(connector)
println "Done."
System.exit(0)
} catch(Exception ex) {
println "caught exception : " + ex
} finally {
connection.close()
}
}
def tickleDaemon = { connector ->
final String TASKS = "tasks"
def connection = connector.connect()
def build = connection.newBuild()
build.forTasks(TASKS)
build.run()
}
}
а другой раздел - основная консоль:
// main -----------
// edit as appropriate
final String TASK_NAME = "runService"
final String GRADLE_INSTALL_DIR = "/Users/measter/tools/gradle-2.14.1"
final String PROJECT_DIR = "../service"
def connector = GradleConnector.newConnector()
connector.useInstallation(new File(GRADLE_INSTALL_DIR))
connector.forProjectDirectory(new File(PROJECT_DIR))
def tokenSource = connector.newCancellationTokenSource()
println "starting ${TASK_NAME}"
def buildRunner = new BuildRunner(connector, tokenSource, TASK_NAME)
new Thread(buildRunner).start()
def console = new Scanner(System.in)
println "Enter a command (S: stop task, Q: quit): "
while (console.hasNextLine()) {
def lineTokenizer = new Scanner(console.nextLine())
String token = lineTokenizer.next()
if (token.equalsIgnoreCase("S")) {
tokenSource.cancel()
} else if (token.equalsIgnoreCase("Q")) {
println "Done."
System.exit(0)
}
}
Этот код можно легко настроить для выполнения других задач, для перезапуска задачи и т.д. Он намекает на прославленную оболочку вокруг использования личной командной строки.
Ответ 3
Вот объяснение от основного разработчика, почему Ctrl + C уничтожит демона.
Это всегда был "по дизайну", но мы хотим отойти от него, чтобы демона так часто не убивали. Я думаю, что есть случаи, когда мы не распространяем ctrl + c, но это удача.
Если вы посмотрите, что мы делаем для непрерывного режима в 2.5, мы добавляем ctrl + d для выхода из процесса Gradle, не убивая демона. У нас есть аналогичная проблема с bootRun с нашей поддержкой приложений Play Play (playRun), которая использует тот же механизм (ctrl + d). Я думаю, что в конечном итоге мы сделаем что-то подобное в целом, но нам нужно предоставить альтернативный способ для существующих скриптов сборки читать stdin, прежде чем мы будем захватывать вход все время.
- Стерлинг Грин (Gradle Core Dev)
Ответ 4
Похоже, это могло быть разрешено в 3.1 https://docs.gradle.org/current/release-notes#more-resilient-daemon
Ответ 5
У меня была та же проблема. Я начал приложение dropwizard и убил демона, чтобы увеличить время перезапуска приложения.
Простое решение:
В конце я просто искал процесс dropwizard и убил его в командной строке (простая комбинация kill и ps aux и grep). Это закрывает приложение и не выполняет сборку, но сохраняет демона.
Ответ 6
bootRun
является удобной функцией spring-boot-gradle-plugin
. Он позволяет выполнять два шага в одной команде, и он имеет очень незначительное преимущество в том, чтобы не генерировать файл .jar
в этом процессе. Он также имеет потенциально большую выгоду...
Если devtools добавлен в ваш проект, он автоматически контролируйте свое приложение для изменений.
Если вы не используете функции прямого обновления bootRun
, , вы можете решить эту проблему, выполнив последовательность сборки/запуска в виде двух команд, как описано в "Запуск приложения" . Поскольку вторая команда не включает Gradle, теперь вы можете Ctrl-C
сервер без недостатка оставить Gradle в состоянии CANCELED
.
Вот пример применения такого подхода:
gradle build && java -jar build/libs/myproject-0.0.1-SNAPSHOT.jar
Если вы используете devtools, вам может не понадобиться часто перезапускать сервер вручную - просто перестройте и перезапустите сервер (для Groovy вам нужно только обновить исходный файл).
Приложения, которые используют spring -boot-devtools, будут автоматически перезагружаться всякий раз, когда изменяются файлы на пути к классам.
./gradlew build -x test