Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Spring BootのGraceful shutdownって内部でどうやって実現されているの?
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
kawakawaryuryu
July 30, 2020
Programming
1.2k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Spring BootのGraceful shutdownって内部でどうやって実現されているの?
JSUG勉強会 2020年その6 LT大会!の発表資料です
kawakawaryuryu
July 30, 2020
More Decks by kawakawaryuryu
See All by kawakawaryuryu
Spring Boot 1.5→2.1バージョンアップを経験して分かったハマりどころ
kawakawaryuryu
1
3.7k
第6章ICMP 第7章Ping
kawakawaryuryu
0
110
第14章DNS
kawakawaryuryu
0
90
逆求人イベント
kawakawaryuryu
0
110
Other Decks in Programming
See All in Programming
iOSDC2026登壇資料.pdf
riofujimon
0
200
Agents on Rails - Rails at Scale 2026
irinanazarova
0
310
モバイル交通系ICへのチャージ実例から考える、クロスプラットフォーム開発におけるiOS実機テスト設計とCI運用
yusuga
1
570
カツオ、ご期待ください
suneo3476
0
140
AI時代のコードレビューは人に向けるな、仕組みに向けろ
texmeijin
5
3.3k
wkhtmltopdfの次どうするか問題2026
willnet
2
1.8k
設計次第でAIコードの読む量は減らせる / designing-for-code-reading
minodriven
33
14k
20260914 AIエージェント時代のPlatform Engineering LLM基盤とプロダクトの責務境界線
kanfab1
7
2.3k
re:Inventに行く前に知っておきたい現地参加のノウハウ
nokomoro3
0
300
Simple Storage Service(S3) is not simple
iwatsukayura
0
120
大喜利で理解するLLM as a Judge / Understanding LLM-as-a-Judge through Ogiri
rockname
0
190
更なる可用性を求めて、5年間運用したKotlinのアプリケーションをGoでリプレイスする話
ken_tunc
0
430
Featured
See All Featured
Design in an AI World
tapps
1
340
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
56
3.5k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.6k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
120
120k
brightonSEO & MeasureFest 2025 - Winning Strategies for Black Friday CRO & PPC - Christian Goodrich
cargoodrich
3
860
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.3k
Embracing the Ebb and Flow
colly
88
5.2k
RailsConf 2023
tenderlove
30
1.6k
HDC tutorial
michielstock
2
930
The browser strikes back
jonoalderson
0
1.7k
Odyssey Design
rkendrick25
PRO
2
850
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
850
Transcript
Spring BootͷGraceful shutdownͬͯ෦ͰͲ͏ͬ ࣮ͯݱ͞Ε͍ͯΔͷʁ 2020/07/30 JSUGษڧձ 2020 ͦͷ6 LTେձ ޱɹཽଠʢ@kawakawaryuryuʣ
Who am I • ޱཽଠʢ@kawakawaryuryuʣ • ϠϑʔגࣜձࣾɹใγεςϜຊ෦ • ࣾձܭγεςϜͷ։ൃ •
࠷ۙ • ϑϩϯτΤϯυͷਓʹͳΓͭͭ͋Δ • Spring৮Εͯͳ͍ 2
Spring Boot 2.3͔ΒGraceful shutdown͕؆୯ʹ • Spring Boot 2.3͔Β؆୯ʹ࣮ݱͰ͖ΔΑ͏ʹͳͬͨ • Jetty,
Reactor Netty, Tomcat, UndertowͰαϙʔτ • ڍಈ • ఀࢭࢦࣔޙɺ৽نϦΫΤετड͚͚ͳ͍ • ॲཧதͷϦΫΤετ͕͔ྃͯ͠ΒαʔόΛఀࢭ͢Δ 3
Graceful shutdown࣮ݱํ๏ • application.ymlʹ2ͭͷϓϩύςΟΛՃ͢Δ͚ͩ • ඇৗʹ؆୯ʂ 4 server: shutdown: graceful
spring: lifecycle: timeout-per-shutdown-phase: 20s #αʔόͷ࠷େγϟοτμϯ࣌ؒ
͜͜Ͱٙ • ෦ͰͲ͏࣮ͬͯݱ͍ͯ͠Δͷʁ • ϒϥοΫϘοΫε͗͢Δɾɾ • ؾʹͳͬͯΕͳ͍ 5
ιʔείʔυͬͯΈ·ͨ͠ • ΰʔϧ • Graceful shutdownͷ࣮ॲཧՕॴΛ֬ೝ͢Δ • Graceful shutdownॲཧ͕ͲͷΑ͏ʹݺΕΔ͔֬ೝ͢Δ •
લఏ • Spring Boot 2.3.1Ͱ֬ೝ • Web ServerJettyͰ֬ೝ 6
·ͣSpring Bootىಈ % ./mvnw spring-boot:run ... . ____ _ __
_ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.1.RELEASE) ... 2020-07-30 02:35:10.626 INFO 15060 --- [ main] o.e.jetty.server.AbstractConnector : Started ServerConnector@552ed807{HTTP/1.1, (http/1.1)}{0.0.0.0:8080} 2020-07-30 02:35:10.628 INFO 15060 --- [ main] o.s.b.web.embedded.jetty.JettyWebServer : Jetty started on port(s) 8080 (http/1.1) with context path '/' 2020-07-30 02:35:10.640 INFO 15060 --- [ main] c.k.s.SampleGracefulShutdownApplication : Started SampleGracefulShutdownApplication in 1.517 seconds (JVM running for 1.795) 7
ΞϓϦΛఀࢭ 2020-07-30 02:35:14.253 INFO 15060 --- [ Thread-223] o.s.b.web.embedded.jetty.JettyWebServer :
Commencing graceful shutdown. Waiting for active requests to complete 2020-07-30 02:35:14.258 INFO 15060 --- [ jetty-shutdown] o.s.b.web.embedded.jetty.JettyWebServer : Graceful shutdown complete 2020-07-30 02:35:14.264 INFO 15060 --- [ Thread-223] o.e.jetty.server.AbstractConnector : Stopped ServerConnector@552ed807{HTTP/1.1, (http/1.1)}{0.0.0.0:8080} 2020-07-30 02:35:14.265 INFO 15060 --- [ Thread-223] org.eclipse.jetty.server.session : node0 Stopped scavenging 2020-07-30 02:35:14.267 INFO 15060 --- [ Thread-223] o.e.j.s.h.ContextHandler.application : Destroying Spring FrameworkServlet 'dispatcherServlet' 2020-07-30 02:35:14.268 INFO 15060 --- [ Thread-223] o.e.jetty.server.handler.ContextHandler : Stopped o.s.b.w.e.j.JettyEmbeddedWebAppContext@38ed139b{application,/,[file:///private/var/folders/ds/ ky2m710d41ldw12zs6jhg4jh0000gn/T/jetty-docbase.10343674703387388779.8080/],UNAVAILABLE} 2020-07-30 02:35:14.270 INFO 15060 --- [ Thread-223] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor' 8
ΞϓϦΛఀࢭ 2020-07-30 02:35:14.253 INFO 15060 --- [ Thread-223] o.s.b.web.embedded.jetty.JettyWebServer :
Commencing graceful shutdown. Waiting for active requests to complete 2020-07-30 02:35:14.258 INFO 15060 --- [ jetty-shutdown] o.s.b.web.embedded.jetty.JettyWebServer : Graceful shutdown complete 2020-07-30 02:35:14.264 INFO 15060 --- [ Thread-223] o.e.jetty.server.AbstractConnector : Stopped ServerConnector@552ed807{HTTP/1.1, (http/1.1)}{0.0.0.0:8080} 2020-07-30 02:35:14.265 INFO 15060 --- [ Thread-223] org.eclipse.jetty.server.session : node0 Stopped scavenging 2020-07-30 02:35:14.267 INFO 15060 --- [ Thread-223] o.e.j.s.h.ContextHandler.application : Destroying Spring FrameworkServlet 'dispatcherServlet' 2020-07-30 02:35:14.268 INFO 15060 --- [ Thread-223] o.e.jetty.server.handler.ContextHandler : Stopped o.s.b.w.e.j.JettyEmbeddedWebAppContext@38ed139b{application,/,[file:///private/var/folders/ds/ ky2m710d41ldw12zs6jhg4jh0000gn/T/jetty-docbase.10343674703387388779.8080/],UNAVAILABLE} 2020-07-30 02:35:14.270 INFO 15060 --- [ Thread-223] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor' 9 ͜ͷΫϥε͕(SBDFGVMTIVUEPXOʹؔΘͬͯͦ͏
JettyWebServerΫϥε • ͜ͷ෦ͰGraceful ShutdownΛߦͬͯͦ͏ 10 public class JettyWebServer implements WebServer
{ @Override public void shutDownGracefully(GracefulShutdownCallback callback) { if (this.gracefulShutdown == null) { callback.shutdownComplete(GracefulShutdownResult.IMMEDIATE); return; } this.gracefulShutdown.shutDownGracefully(callback); } } UIJTHSBDFGVM4IVUEPXOΠϯελϯε͕OVMMͰͳ͍ ߹ʹ(SBDFGVMTIVUEPXOΛߦ͏
GracefulShutdownΫϥε 11 void shutDownGracefully(GracefulShutdownCallback callback) { logger.info("Commencing graceful shutdown. Waiting
for active requests to complete"); for (Connector connector : this.server.getConnectors()) { shutdown(connector); // (1) } this.shuttingDown = true; new Thread(() -> awaitShutdown(callback), "jetty-shutdown").start(); // (2) } ΞϓϦΛఀࢭͨ࣌͠ʹग़ྗ͞Εͨϩάͱಉ͡ Γ͜ͷ෦Ͱ(SBDFGVMTIVUEPXOͷॲཧΛͯͦ͠͏ ͔͜͜ΒઌͷॲཧεϥΠυͷ࠷ޙʹࡌ͚ͬͯ͋Γ·͢
JettyWebServerΫϥεʢ࠶ܝʣ • ͜ͷ෦ͰGraceful shutdownΛߦ͍ͬͯͦ͏ͳ͜ͱ͔ͬͨ • ͍ͭࣗ͜ମͲ͔͜ΒݺΕ͍ͯΔʁ 12 public class JettyWebServer
implements WebServer { @Override public void shutDownGracefully(GracefulShutdownCallback callback) { if (this.gracefulShutdown == null) { callback.shutdownComplete(GracefulShutdownResult.IMMEDIATE); return; } this.gracefulShutdown.shutDownGracefully(callback); } }
WebServerGracefulShutdownLifecycle • ্هΫϥεͷstopϝιουͰݺΕΔ • SmartLifecycleͷstopϝιουΛΦʔόʔϥΠυ͍ͯ͠Δ 13 class WebServerGracefulShutdownLifecycle implements SmartLifecycle
{ @Override public void stop(Runnable callback) { this.running = false; this.webServer.shutDownGracefully((result) -> callback.run()); } }
SmartLifecycleʁ 14 https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/SmartLifecycle.html
SmartLifecycle • Graceful shutdownͷॲཧΛݺͼग़͍ͯ͠Δਖ਼ମ͜Ε • SmartLifecycleΛ࣮ͨ͠ΫϥεApplicationContextͷىಈ࣌ ఀࢭ࣌ʹҙͷॲཧ͕ݺΕΔ 15
SmartLifecycleͷ࣮ 16 public class SampleSmartLifecycle implements SmartLifecycle { @Override public
void start() { // ىಈ࣌ͷҙॲཧΛ࣮ } @Override public void stop() { // ఀࢭ࣌ͷҙॲཧΛ࣮ } @Override public void stop(Runnable callback) { // ఀࢭ࣌ͷҙॲཧΛ࣮ // callbackΛड͚औͬͯ͞Εͨॲཧͷݺͼग़͕͠Մೳ } @Override public boolean isRunning() { // ίϯϙʔωϯτ͕Քಇதͷ߹ʹtrueΛฦ͢Α͏ʹ࣮ } } (SBDFGVMTIVUEPXOͰ͜ͷϝιουΛ ΦʔόʔϥΠυ͍ͯͨ͠
17 "QQMJDBUJPO$POUFYUΫϩʔζ࣌ʹ #FBOొ͞Ε͍ͯΔ4NBSU-JGFDZDMFͷ TUPQϝιουΛॱ൪ʹݺΜͰ͍͘
·ͱΊ • Spring BootͷGraceful shutdownSmartLifecycleͱ͍͏ΈΛ ͬͯApplicationContextͷఀࢭ࣌ʹݺͼग़͞ΕΔ • IDEΛۦ͢ΕSpring BootͷιʔείʔυׂͱಡΊΔͷͰ ͔Βͳ͍ͱ͖ಡΜͰΈΔͷ͕͓͢͢Ί
18
ઌQiitaʹهࣄΛॻ͖·ͨ͠ 19 https://qiita.com/kawakawaryuryu/items/d0cfd1bb1ec0402fd6c8
͝ਗ਼ௌ͋Γ͕ͱ͏ ͍͟͝·ͨ͠
͓·͚ JettyͷGraceful shutdown ࣮ॲཧՕॴͷ֬ೝ
GracefulShutdownΫϥε 22 void shutDownGracefully(GracefulShutdownCallback callback) { logger.info("Commencing graceful shutdown. Waiting
for active requests to complete"); for (Connector connector : this.server.getConnectors()) { shutdown(connector); // (1) } this.shuttingDown = true; new Thread(() -> awaitShutdown(callback), "jetty-shutdown").start(); // (2) } ΞϓϦΛఀࢭͨ࣌͠ʹग़ྗ͞Εͨϩάͱಉ͡
(1) ৽نϦΫΤετडΛఀࢭ͢Δॲཧ 23 void shutDownGracefully(GracefulShutdownCallback callback) { for (Connector connector
: this.server.getConnectors()) { shutdown(connector); // (1) } } private void shutdown(Connector connector) { try { connector.shutdown().get(); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } catch (ExecutionException ex) { // Continue } } αʔό͕࣋ͭશίωΫλΛॱ൪ʹ ఀࢭ͍ͯ͘͠ ˠ৽نίωΫγϣϯͷडΛఀࢭ
(2) ॲཧதͷϦΫΤετͷྃޙ αʔόΛఀࢭ͢Δॲཧ 24 private void awaitShutdown(GracefulShutdownCallback callback) { while
(this.shuttingDown && this.activeRequests.get() > 0) { sleep(100); } this.shuttingDown = false; long activeRequests = this.activeRequests.get(); if (activeRequests == 0) { logger.info("Graceful shutdown complete"); callback.shutdownComplete(GracefulShutdownResult.IDLE); } else { logger.info(LogMessage.format("Graceful shutdown aborted with %d request(s) still active", activeRequests)); callback.shutdownComplete(GracefulShutdownResult.REQUESTS_ACTIVE); } } ΞΫςΟϒͳϦΫΤετ͕ͳ͘ͳΔ ·ͰTMFFQͭͭ͠ϧʔϓΛճ͢
(2) ॲཧதͷϦΫΤετͷྃޙ αʔόΛఀࢭ͢Δॲཧ 25 private void awaitShutdown(GracefulShutdownCallback callback) { while
(this.shuttingDown && this.activeRequests.get() > 0) { sleep(100); } this.shuttingDown = false; long activeRequests = this.activeRequests.get(); if (activeRequests == 0) { logger.info("Graceful shutdown complete"); callback.shutdownComplete(GracefulShutdownResult.IDLE); } else { logger.info(LogMessage.format("Graceful shutdown aborted with %d request(s) still active", activeRequests)); callback.shutdownComplete(GracefulShutdownResult.REQUESTS_ACTIVE); } } ΞΫςΟϒͳϦΫΤετ͕ʹͳͬͨΒ γϟοτμϯ ˠॲཧதͷϦΫΤετΛ͔ྃͯ͠Β ҆શʹఀࢭ