วิธีปิด Spring Boot Application ด้วยวิธีที่ถูกต้อง?


121

ในเอกสาร Spring Boot พวกเขากล่าวว่า 'SpringApplication แต่ละตัวจะลงทะเบียน hook การปิดระบบกับ JVM เพื่อให้แน่ใจว่า ApplicationContext ปิดอย่างเรียบร้อยเมื่อออกจากระบบ'

เมื่อฉันคลิกctrl+cที่คำสั่งเชลล์แอปพลิเคชันสามารถปิดได้อย่างสวยงาม java -jar ProApplicaton.jarถ้าผมเรียกใช้โปรแกรมประยุกต์ในเครื่องการผลิตที่ผมต้องใช้คำสั่ง แต่ฉันปิดเทอร์มินัลเชลล์ไม่ได้มิฉะนั้นจะปิดกระบวนการ

ถ้าฉันเรียกใช้คำสั่งเช่นnohup java -jar ProApplicaton.jar &ฉันไม่สามารถใช้ctrl+cเพื่อปิดได้อย่างสง่างาม

วิธีที่ถูกต้องในการเริ่มและหยุด Spring Boot Application ในสภาพแวดล้อมการผลิตคืออะไร?


ขึ้นอยู่กับการกำหนดค่าของคุณ PID ​​ของแอปพลิเคชันจะถูกเขียนลงในไฟล์ คุณสามารถส่งสัญญาณฆ่าไปยัง PID นั้นได้ ดูความคิดเห็นในฉบับนี้ด้วย
M. Deinum

ฉันควรใช้สัญญาณไหนฉันไม่คิดว่า kill -9 เป็นความคิดที่ดีใช่มั้ย?
คริส

5
นั่นคือเหตุผลที่ฉันชี้ให้คุณไปที่กระทู้นั้น ... แต่สิ่งที่kill -SIGTERM <PID>ควรทำคือเคล็ดลับ
M. Deinum

kill with pid, no -9
Dapeng

1
kill $ (lsof -ti tcp: <port>) - ในกรณีที่คุณไม่ต้องการใช้แอคชูเอเตอร์และต้องการการฆ่าอย่างรวดเร็ว
Alex Nolasco

คำตอบ:


63

หากคุณกำลังใช้โมดูลแอคชูเอเตอร์คุณสามารถปิดแอปพลิเคชันผ่านJMXหรือHTTPหากเปิดใช้งานปลายทาง

เพิ่มในapplication.properties:

endpoints.shutdown.enabled = true

URL ต่อไปนี้จะพร้อมใช้งาน:

/actuator/shutdown - อนุญาตให้ปิดแอปพลิเคชันอย่างสง่างาม (ไม่ได้เปิดใช้งานโดยค่าเริ่มต้น)

พารามิเตอร์ที่ละเอียดอ่อนอาจถูกใช้เป็นคำใบ้ความปลอดภัยทั้งนี้ขึ้นอยู่กับวิธีการเปิดเผยจุดสิ้นสุด

ตัวอย่างเช่นปลายทางที่ละเอียดอ่อนจะต้องใช้ชื่อผู้ใช้ / รหัสผ่านเมื่อมีการเข้าถึงHTTP(หรือปิดการใช้งานหากไม่ได้เปิดใช้งานความปลอดภัยของเว็บ)

จากเอกสาร Spring boot


1
ฉันไม่ต้องการรวมโมดูลแอคชูเอเตอร์ แต่ฉันพบว่าในบันทึกคอนโซลของฉัน Spring Boot พิมพ์ PID ในบรรทัดแรก มีวิธีใดบ้างที่จะให้ Spring Boot พิมพ์ PID ในไฟล์อื่นโดยไม่ต้องเพิ่มโมดูลตัวกระตุ้น (ApplicationPidListener)
คริส

2
โปรดทราบว่าสิ่งนี้จะต้องเป็นโพสต์ http ไปยังปลายทางนี้ คุณสามารถเปิดใช้งานได้ด้วย endpoints.shutdown.enabled = true
sparkyspider

54

นี่คืออีกทางเลือกหนึ่งที่ไม่ต้องการให้คุณเปลี่ยนรหัสหรือเปิดเผยจุดสิ้นสุดการปิดเครื่อง สร้างสคริปต์ต่อไปนี้และใช้เพื่อเริ่มและหยุดแอปของคุณ

start.sh

#!/bin/bash
java -jar myapp.jar & echo $! > ./pid.file &

เริ่มต้นแอปของคุณและบันทึกรหัสกระบวนการในไฟล์

stop.sh

#!/bin/bash
kill $(cat ./pid.file)

หยุดแอปของคุณโดยใช้รหัสกระบวนการที่บันทึกไว้

start_silent.sh

#!/bin/bash
nohup ./start.sh > foo.out 2> foo.err < /dev/null &

หากคุณต้องการเริ่มแอปโดยใช้ ssh จากเครื่องระยะไกลหรือไปป์ไลน์ CI ให้ใช้สคริปต์นี้แทนเพื่อเริ่มแอปของคุณ การใช้ start.sh โดยตรงสามารถปล่อยให้เชลล์ค้างได้

หลังจากเช่น การปรับใช้แอปของคุณใหม่คุณสามารถรีสตาร์ทได้โดยใช้:

sshpass -p password ssh -oStrictHostKeyChecking=no userName@www.domain.com 'cd /home/user/pathToApp; ./stop.sh; ./start_silent.sh'

นี่น่าจะเป็นคำตอบ ฉันเพิ่งยืนยันว่าการปิดเครื่อง 15 สัญญาณบอกให้ฤดูใบไม้ผลิปิดตัวลงอย่างสง่างาม
ชาด

1
ทำไมคุณไม่เรียกการเรียกใช้ java - jar ด้วย nohup ภายใน start.sh แทนที่จะเรียกการเรียกใช้ java - jar ภายใน start.sh ซึ่งเรียกด้วย nohup ภายในสคริปต์เปลือกนอกอื่น ??
Anand Varkey Philips

2
@AnandVarkeyPhilips เหตุผลเดียวคือบางครั้งฉันเรียก start.sh จากบรรทัดคำสั่งเพื่อวัตถุประสงค์ในการทดสอบ แต่ถ้าคุณต้องการเสมอnohupคุณก็สามารถรวมคำสั่งได้
Jens

@Jens ขอบคุณสำหรับข้อมูล คุณบอกฉันได้ไหมว่าคุณทำสิ่งนี้: foo.out 2> foo.err </ dev / null &
Anand Varkey Philips

1
@jens ขอบคุณที่ฉันทำมันสำเร็จและฉันได้โพสต์สคริปต์เริ่มต้นและหยุดที่นี่ด้านล่าง ( stackoverflow.com/questions/26547532/… )
Anand Varkey Philips

52

สำหรับคำตอบของ @ Jean-Philippe Bond

นี่คือตัวอย่างด่วนของ maven สำหรับผู้ใช้ maven ในการกำหนดค่าจุดสิ้นสุด HTTP เพื่อปิดแอปเว็บสปริงบูตโดยใช้ spring-boot-starter-actuator เพื่อให้คุณสามารถคัดลอกและวาง:

1. มาเวน pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2.application.properties:

#No auth  protected 
endpoints.shutdown.sensitive=false

#Enable shutdown endpoint
endpoints.shutdown.enabled=true

จุดสิ้นสุดทั้งหมดแสดงอยู่ที่นี่ :

3. ส่งวิธีการโพสต์เพื่อปิดแอป:

curl -X POST localhost:port/shutdown

หมายเหตุด้านความปลอดภัย:

หากคุณต้องการวิธีการปิดระบบรับรองความถูกต้องคุณอาจต้องใช้

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

กำหนดค่ารายละเอียด :


หลังจากขั้นตอนที่สองเมื่อพยายามปรับใช้พบข้อความแสดงข้อผิดพลาดนี้: คำอธิบาย: พารามิเตอร์ 0 ของเมธอด setAuthenticationConfiguration ใน org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter ต้องการ bean ประเภท 'org.springframework.security.config .annotation.authentication.configuration.AuthenticationConfiguration 'ที่ไม่พบ การดำเนินการ: พิจารณากำหนดชนิด bean 'org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration' ในคอนฟิกูเรชันของคุณ
Roberto

2
โปรดทราบ: หากฉันได้รวมสิ่งที่ต้องการserver.contextPath=/appNameไว้ใน application.properties ของฉันดังนั้นตอนนี้คำสั่งปิดระบบจะกลายเป็น: curl -X POST localhost:8080/appName/shutdown หวังว่ามันอาจช่วยใครบางคนได้ ฉันต้องดิ้นรนมากเพราะความผิดพลาดนี้
Naveen Kumar

กับฤดูใบไม้ผลิ Boot 1.5.8 มันก็บอกถ้าได้โดยไม่ต้องรักษาความปลอดภัยที่มีอยู่ใน endpoints.shutdown.enabled=true management.security.enabled=falseapplication.properties
Stefano Scarpanti

หากคุณไม่ต้องการเปิดเผยจุดสิ้นสุดและใช้ไฟล์ PID เพื่อหยุดและเริ่มต้นผ่านเชลล์สคริปต์ลองสิ่งนี้: stackoverflow.com/questions/26547532/…
Anand Varkey Philips

27

คุณสามารถทำให้แอปพลิเคชัน springboot เขียน PID ลงในไฟล์และคุณสามารถใช้ไฟล์ pid เพื่อหยุดหรือรีสตาร์ทหรือรับสถานะโดยใช้สคริปต์ทุบตี ในการเขียน PID ลงในไฟล์ให้ลงทะเบียนผู้ฟังกับ SpringApplication โดยใช้ ApplicationPidFileWriter ดังที่แสดงด้านล่าง:

SpringApplication application = new SpringApplication(Application.class);
application.addListeners(new ApplicationPidFileWriter("./bin/app.pid"));
application.run();

จากนั้นเขียนสคริปต์ทุบตีเพื่อเรียกใช้แอปพลิเคชันสปริงบูต ข้อมูลอ้างอิง .

ตอนนี้คุณสามารถใช้สคริปต์เพื่อเริ่มหยุดหรือรีสตาร์ทได้


สามารถพบการเริ่มต้นและหยุดเชลล์สคริปต์ที่สมบูรณ์แบบทั่วไปและเจนกินส์ได้ที่นี่ ( stackoverflow.com/questions/26547532/… )
Anand Varkey Philips


14

คำตอบทั้งหมดดูเหมือนจะขาดความจริงที่ว่าคุณอาจต้องทำงานบางส่วนให้เสร็จสมบูรณ์ในรูปแบบที่ประสานกันระหว่างการปิดระบบอย่างสง่างาม (เช่นในแอปพลิเคชันระดับองค์กร)

@PreDestroyอนุญาตให้คุณรันโค้ดปิดในถั่วแต่ละอัน สิ่งที่ซับซ้อนกว่านี้จะมีลักษณะดังนี้:

@Component
public class ApplicationShutdown implements ApplicationListener<ContextClosedEvent> {
     @Autowired ... //various components and services

     @Override
     public void onApplicationEvent(ContextClosedEvent event) {
         service1.changeHeartBeatMessage(); // allows loadbalancers & clusters to prepare for the impending shutdown
         service2.deregisterQueueListeners();
         service3.finishProcessingTasksAtHand();
         service2.reportFailedTasks();
         service4.gracefullyShutdownNativeSystemProcessesThatMayHaveBeenLaunched(); 
         service1.eventLogGracefulShutdownComplete();
     }
}

นี่เป็นเพียงสิ่งที่ฉันต้องการ หลังจากเรียกใช้แอปพลิเคชันแล้วให้กด ctrl-c ขอบคุณ @Michal
Claudio Moscoso

8

ฉันไม่เปิดเผยจุดสิ้นสุดใด ๆ และเริ่มต้น ( ด้วย nohup ในพื้นหลังและไม่มีไฟล์ที่สร้างผ่าน nohup ) และหยุดด้วยเชลล์สคริปต์ (ด้วยKILL PID อย่างสง่างามและบังคับให้ฆ่าหากแอปยังคงทำงานอยู่หลังจาก 3 นาที ) ฉันเพิ่งสร้าง jar ที่เรียกใช้งานได้และใช้ตัวเขียนไฟล์ PID เพื่อเขียนไฟล์ PID และจัดเก็บ Jar และ Pid ในโฟลเดอร์ที่มีชื่อเดียวกับชื่อแอปพลิเคชันและเชลล์สคริปต์ก็มีชื่อเดียวกันโดยเริ่มต้นและหยุดในตอนท้าย ฉันเรียกสคริปต์หยุดเหล่านี้และเริ่มสคริปต์ผ่านทางท่อเจนกินส์ด้วย ยังไม่มีปัญหา ทำงานได้อย่างสมบูรณ์แบบสำหรับ 8 แอปพลิเคชัน (สคริปต์ทั่วไปมากและใช้งานง่ายสำหรับแอปใด ๆ )

ชั้นเรียนหลัก

@SpringBootApplication
public class MyApplication {

    public static final void main(String[] args) {
        SpringApplicationBuilder app = new SpringApplicationBuilder(MyApplication.class);
        app.build().addListeners(new ApplicationPidFileWriter());
        app.run();
    }
}

ไฟล์ YML

spring.pid.fail-on-write-error: true
spring.pid.file: /server-path-with-folder-as-app-name-for-ID/appName/appName.pid

นี่คือสคริปต์เริ่มต้น (start-appname.sh):

#Active Profile(YAML)
ACTIVE_PROFILE="preprod"
# JVM Parameters and Spring boot initialization parameters
JVM_PARAM="-Xms512m -Xmx1024m -Dspring.profiles.active=${ACTIVE_PROFILE} -Dcom.webmethods.jms.clientIDSharing=true"
# Base Folder Path like "/folder/packages"
CURRENT_DIR=$(readlink -f "$0")
BASE_PACKAGE="${CURRENT_DIR%/bin/*}"
# Shell Script file name after removing path like "start-yaml-validator.sh"
SHELL_SCRIPT_FILE_NAME=$(basename -- "$0")
# Shell Script file name after removing extension like "start-yaml-validator"
SHELL_SCRIPT_FILE_NAME_WITHOUT_EXT="${SHELL_SCRIPT_FILE_NAME%.sh}"
# App name after removing start/stop strings like "yaml-validator"
APP_NAME=${SHELL_SCRIPT_FILE_NAME_WITHOUT_EXT#start-}

PIDS=`ps aux |grep [j]ava.*-Dspring.profiles.active=$ACTIVE_PROFILE.*$APP_NAME.*jar | awk {'print $2'}`
if [ -z "$PIDS" ]; then
  echo "No instances of $APP_NAME with profile:$ACTIVE_PROFILE is running..." 1>&2
else
  for PROCESS_ID in $PIDS; do
        echo "Please stop the process($PROCESS_ID) using the shell script: stop-$APP_NAME.sh"
  done
  exit 1
fi

# Preparing the java home path for execution
JAVA_EXEC='/usr/bin/java'
# Java Executable - Jar Path Obtained from latest file in directory
JAVA_APP=$(ls -t $BASE_PACKAGE/apps/$APP_NAME/$APP_NAME*.jar | head -n1)
# To execute the application.
FINAL_EXEC="$JAVA_EXEC $JVM_PARAM -jar $JAVA_APP"
# Making executable command using tilde symbol and running completely detached from terminal
`nohup $FINAL_EXEC  </dev/null >/dev/null 2>&1 &`
echo "$APP_NAME start script is  completed."

นี่คือสคริปต์หยุด (stop-appname.sh):

#Active Profile(YAML)
ACTIVE_PROFILE="preprod"
#Base Folder Path like "/folder/packages"
CURRENT_DIR=$(readlink -f "$0")
BASE_PACKAGE="${CURRENT_DIR%/bin/*}"
# Shell Script file name after removing path like "start-yaml-validator.sh"
SHELL_SCRIPT_FILE_NAME=$(basename -- "$0")
# Shell Script file name after removing extension like "start-yaml-validator"
SHELL_SCRIPT_FILE_NAME_WITHOUT_EXT="${SHELL_SCRIPT_FILE_NAME%.*}"
# App name after removing start/stop strings like "yaml-validator"
APP_NAME=${SHELL_SCRIPT_FILE_NAME_WITHOUT_EXT:5}

# Script to stop the application
PID_PATH="$BASE_PACKAGE/config/$APP_NAME/$APP_NAME.pid"

if [ ! -f "$PID_PATH" ]; then
   echo "Process Id FilePath($PID_PATH) Not found"
else
    PROCESS_ID=`cat $PID_PATH`
    if [ ! -e /proc/$PROCESS_ID -a /proc/$PROCESS_ID/exe ]; then
        echo "$APP_NAME was not running with PROCESS_ID:$PROCESS_ID.";
    else
        kill $PROCESS_ID;
        echo "Gracefully stopping $APP_NAME with PROCESS_ID:$PROCESS_ID..."
        sleep 5s
    fi
fi
PIDS=`/bin/ps aux |/bin/grep [j]ava.*-Dspring.profiles.active=$ACTIVE_PROFILE.*$APP_NAME.*jar | /bin/awk {'print $2'}`
if [ -z "$PIDS" ]; then
  echo "All instances of $APP_NAME with profile:$ACTIVE_PROFILE has has been successfully stopped now..." 1>&2
else
  for PROCESS_ID in $PIDS; do
    counter=1
    until [ $counter -gt 150 ]
        do
            if ps -p $PROCESS_ID > /dev/null; then
                echo "Waiting for the process($PROCESS_ID) to finish on it's own for $(( 300 - $(( $counter*5)) ))seconds..."
                sleep 2s
                ((counter++))
            else
                echo "$APP_NAME with PROCESS_ID:$PROCESS_ID is stopped now.."
                exit 0;
            fi
    done
    echo "Forcefully Killing $APP_NAME with PROCESS_ID:$PROCESS_ID."
    kill -9 $PROCESS_ID
  done
fi

7

Spring Boot ให้ตัวฟังแอปพลิเคชันหลายตัวในขณะที่พยายามสร้างบริบทของแอปพลิเคชันหนึ่งในนั้นคือ ApplicationFailedEvent เราสามารถใช้เพื่อทราบสภาพอากาศว่าบริบทของแอปพลิเคชันเริ่มต้นหรือไม่

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.boot.context.event.ApplicationFailedEvent; 
    import org.springframework.context.ApplicationListener;

    public class ApplicationErrorListener implements 
                    ApplicationListener<ApplicationFailedEvent> {

        private static final Logger LOGGER = 
        LoggerFactory.getLogger(ApplicationErrorListener.class);

        @Override
        public void onApplicationEvent(ApplicationFailedEvent event) {
           if (event.getException() != null) {
                LOGGER.info("!!!!!!Looks like something not working as 
                                expected so stoping application.!!!!!!");
                         event.getApplicationContext().close();
                  System.exit(-1);
           } 
        }
    }

เพิ่มไปยังคลาสผู้ฟังด้านบนใน SpringApplication

    new SpringApplicationBuilder(Application.class)
            .listeners(new ApplicationErrorListener())
            .run(args);  

คำตอบที่ดีที่สุดที่ฉันพบ! ขอบคุณ!
Vagif

[@ user3137438] แตกต่างจากการบันทึกในคำอธิบายประกอบก่อนทำลายอย่างไร
Anand Varkey Philips

6

ตั้งแต่ Spring Boot 2.3ขึ้นไปมีกลไกการปิดเครื่องที่สวยงามในตัว

Pre-Spring Boot 2.3ไม่มีกลไกการปิดที่สง่างามนอกกรอบ สปริงบูตบางตัวมีฟังก์ชันนี้:

  1. https://github.com/jihor/hiatus-spring-boot
  2. https://github.com/gesellix/graceful-shutdown-spring-boot
  3. https://github.com/corentin59/spring-boot-graceful-shutdown

ฉันเป็นผู้แต่ง nr. 1. สตาร์ทเตอร์มีชื่อว่า "Hiatus for Spring Boot" มันทำงานในระดับโหลดบาลานเซอร์กล่าวคือทำเครื่องหมายบริการเป็น OUT_OF_SERVICE โดยไม่รบกวนบริบทของแอปพลิเคชัน แต่อย่างใด สิ่งนี้ช่วยให้สามารถปิดเครื่องได้อย่างสง่างามและหมายความว่าหากจำเป็นบริการนี้สามารถหยุดให้บริการได้สักระยะหนึ่งแล้วกลับมามีชีวิตอีกครั้ง ข้อเสียคือมันไม่ได้หยุด JVM คุณจะต้องทำด้วยkillคำสั่ง ในขณะที่ฉันทำงานทุกอย่างในคอนเทนเนอร์นี่ไม่ใช่เรื่องใหญ่สำหรับฉันเพราะฉันจะต้องหยุดและนำคอนเทนเนอร์ออกอยู่ดี

เลขที่ 2 และ 3 มากหรือน้อยอ้างอิงจากโพสต์นี้โดย Andy Wilkinson พวกเขาทำงานทางเดียว - เมื่อถูกกระตุ้นในที่สุดพวกเขาก็ปิดบริบท


5

SpringApplication ลงทะเบียน hook การปิดระบบด้วย JVM โดยปริยายเพื่อให้แน่ใจว่า ApplicationContext ปิดอย่างเรียบร้อยเมื่อออก @PreDestroyที่ยังจะเรียกวิธีถั่วทุกข้อเขียนด้วย นั่นหมายความว่าเราไม่จำเป็นต้องใช้registerShutdownHook()เมธอดของConfigurableApplicationContextแอปพลิเคชันในการบู๊ตอย่างชัดเจน เช่นที่เราต้องทำในแอปพลิเคชันแกนสปริง

@SpringBootConfiguration
public class ExampleMain {
    @Bean
    MyBean myBean() {
        return new MyBean();
    }

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(ExampleMain.class, args);
        MyBean myBean = context.getBean(MyBean.class);
        myBean.doSomething();

        //no need to call context.registerShutdownHook();
    }

    private static class MyBean {

        @PostConstruct
        public void init() {
            System.out.println("init");
        }

        public void doSomething() {
            System.out.println("in doSomething()");
        }

        @PreDestroy
        public void destroy() {
            System.out.println("destroy");
        }
    }
}

เป็นอีกทางเลือกหนึ่ง@PostConstructและ@PreDestroyฉันใช้แอตทริบิวต์initMethodand destroyMethodภายใน@Beanคำอธิบายประกอบ สำหรับตัวอย่างนี้: @Bean(initMethod="init", destroyMethod="destroy").
acker9

สิ่งหนึ่งที่@PreDestroyนักพัฒนาอาจไม่ทราบก็คือวิธีการดังกล่าวเรียกว่า bean ที่มีขอบเขต Singleton เท่านั้น นักพัฒนาต้องจัดการส่วนการล้างข้อมูลของวงจรชีวิตของถั่วสำหรับขอบเขตอื่น ๆ
asgs

2

มีหลายวิธีในการปิดแอปพลิเคชันสปริง หนึ่งคือการโทรปิด () บนApplicationContext:

ApplicationContext ctx =
    SpringApplication.run(HelloWorldApplication.class, args);
// ...
ctx.close()

คำถามของคุณแนะนำให้คุณต้องการปิดแอปพลิเคชันของคุณโดยทำCtrl+Cซึ่งมักใช้ในการยุติคำสั่ง ในกรณีนี้...

ใช้endpoints.shutdown.enabled=trueไม่ใช่สูตรที่ดีที่สุด หมายความว่าคุณเปิดเผยจุดสิ้นสุดเพื่อยุติการสมัครของคุณ ดังนั้นขึ้นอยู่กับกรณีการใช้งานและสภาพแวดล้อมของคุณคุณจะต้องรักษาความปลอดภัย ...

Ctrl+Cควรทำงานได้ดีในกรณีของคุณ ฉันถือว่าปัญหาของคุณเกิดจากเครื่องหมายและ (&) คำอธิบายเพิ่มเติม:

Spring Application Context อาจมีการลงทะเบียน hook การปิดระบบกับรันไทม์ JVM โปรดดูเอกสาร ApplicationContext

ฉันไม่รู้ว่า Spring Boot กำหนดค่า hook นี้โดยอัตโนมัติตามที่คุณพูดหรือไม่ ฉันคิดว่ามันเป็น

บนCtrl+Cเชลล์ของคุณส่งINTสัญญาณไปยังแอปพลิเคชันเบื้องหน้า หมายความว่า "โปรดขัดจังหวะการดำเนินการของคุณ" แอปพลิเคชันสามารถดักจับสัญญาณนี้และทำการล้างข้อมูลก่อนที่จะยุติ (เบ็ดที่ลงทะเบียนโดย Spring) หรือเพียงแค่เพิกเฉย (ไม่ดี)

nohupคือคำสั่งที่รันโปรแกรมต่อไปนี้โดยใช้กับดักเพื่อละเว้นสัญญาณ HUP HUP ใช้เพื่อยุติโปรแกรมเมื่อคุณวางสาย (เช่นปิด ssh connexion ของคุณ) นอกจากนี้ยังเปลี่ยนเส้นทางเอาต์พุตเพื่อหลีกเลี่ยงไม่ให้โปรแกรมของคุณบล็อกบน TTY ที่หายไป nohupไม่ละเว้นสัญญาณ INT ดังนั้นจึงไม่ขัดขวางCtrl+Cการทำงาน

ฉันถือว่าปัญหาของคุณเกิดจากเครื่องหมายและ (&) ไม่ใช่จาก nohup Ctrl+Cส่งสัญญาณไปยังกระบวนการเบื้องหน้า เครื่องหมายและทำให้แอปพลิเคชันของคุณทำงานในพื้นหลัง ทางออกเดียว: ทำ

kill -INT pid

ใช้kill -9หรือkill -KILLไม่ดีเนื่องจากแอปพลิเคชัน (ในที่นี้คือ JVM) ไม่สามารถดักจับให้ยุติได้อย่างสง่างาม

อีกวิธีหนึ่งคือการนำแอปพลิเคชันของคุณกลับมาใช้งานล่วงหน้า แล้วCtrl+Cจะทำงาน. fgมีลักษณะที่ควบคุมทุบตีงานอย่างแม่นยำมากขึ้นบน


2

ใช้exit()วิธีการคงที่ในคลาส SpringApplication เพื่อปิดแอปพลิเคชันสปริงบูตของคุณอย่างสง่างาม

public class SomeClass {
    @Autowire
    private ApplicationContext context

    public void close() {
        SpringApplication.exit(context);
    }
}

สิ่งนี้ใช้ได้กับฉัน ขอบคุณมาก.
ขจรจิตรส่องแสน

1

Spring Boot รองรับการปิดเครื่องได้อย่างสวยงาม (ปัจจุบันอยู่ในเวอร์ชันก่อนวางจำหน่าย 2.3.0.BUILD-SNAPSHOT)

เมื่อเปิดใช้งานการปิดแอปพลิเคชันจะรวมช่วงเวลาผ่อนผันของระยะเวลาที่กำหนดได้ ในช่วงระยะเวลาผ่อนผันนี้คำขอที่มีอยู่จะได้รับอนุญาตให้ดำเนินการให้เสร็จสมบูรณ์ แต่จะไม่มีการอนุญาตคำขอใหม่

คุณสามารถเปิดใช้งานได้ด้วย:

server.shutdown.grace-period=30s

https://docs.spring.io/spring-boot/docs/2.3.0.BUILD-SNAPSHOT/reference/html/spring-boot-features.html#boot-features-graceful-shutdown


0

หากคุณกำลังใช้ Maven คุณสามารถใช้ปลั๊กอินประกอบ Maven App

daemon mojo (ซึ่งฝังJSW ) จะส่งออกเชลล์สคริปต์พร้อมอาร์กิวเมนต์ start / stop stopปิดประสงค์ / ฆ่าได้อย่างสง่างามแอพลิเคชันฤดูใบไม้ผลิของคุณ

สามารถใช้สคริปต์เดียวกันเพื่อใช้แอปพลิเคชัน maven ของคุณเป็นบริการ linux


0

หากคุณอยู่ในสภาพแวดล้อม linux สิ่งที่คุณต้องทำคือสร้าง symlink ไปยังไฟล์. jar ของคุณจากภายใน /etc/init.d/

sudo ln -s /path/to/your/myboot-app.jar /etc/init.d/myboot-app

จากนั้นคุณสามารถเริ่มแอปพลิเคชันเหมือนกับบริการอื่น ๆ

sudo /etc/init.d/myboot-app start

เพื่อปิดแอปพลิเคชัน

sudo /etc/init.d/myboot-app stop

ด้วยวิธีนี้แอปพลิเคชันจะไม่สิ้นสุดเมื่อคุณออกจากเครื่อง และแอปพลิเคชันจะปิดลงอย่างสง่างามด้วยคำสั่งหยุด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.