iT邦幫忙

2024 iThome 鐵人賽

DAY 8
0

在上一章節理解優雅關閉(Gracefule shutdown)相關概念,此章節會透過 Quarkus 進行實作。實作內容會有

  1. PostgreSQL
  2. Quarkus 應用程式
  3. 觀察 Kubernetes 和 Quarkus 兩者不同設定

主要探討當 Quarkus 收到一個像是裝置資訊時,應用程式會進行電池檢查。會聚焦於如果該電量小於 30 時會寄送郵件且會將該筆裝置資訊儲存至 PostgreSQL 裡面。假設突然故障時,能否繼續將最後請求給安全處理完畢,且不再接收外部流量。

首先,先建置環境,透過以下建置 PostgreSQL 和 EMQX。

docker compose -f infra/docker-compose.yaml up -d

實作內容有實現一個 API,該 API 可以即時收到每筆裝置訊息。程式碼細節這邊不會特別論述,例如 @Channel 等關鍵字。

@Path("/device")
public class DeviceResource {

    @Inject
    @Channel("my-data-stream")
    Publisher<DeviceSimulation> data;


    @GET
    @Path("stream")
    @Produces(MediaType.SERVER_SENT_EVENTS)
    public Publisher<DeviceSimulation> stream() {
        return data;
    }
}

接下來是最重要的業務邏輯,當中使用 log 方式代替寄信,因此會先停頓 5 秒,後這在停頓 6 秒將異常電量儲存至資料庫。這邊將會是觀察重點。

@ApplicationScoped
public class AlertConsumer {
    @Inject
    Logger Log;

    @Transactional
    @Incoming("my-data-stream")
    @Blocking
    public void process(DeviceSimulation data) {
        if (data.battery() < 30) {
            var alert = new AlertMessage("LOW", "battery to Low");
            try {
                Log.infof("Sleep 5 s.");
                Thread.sleep(5000); // Not blocking the IO thread anymore
                Log.infof("Send email to %s", data.name());
                Log.infof("Sleep 6 s.");
                Thread.sleep(6000);
                new Alert(alert.Level(), alert.message(), data.battery(), Instant.ofEpochMilli(data.create())).persistAndFlush();
                Log.infof("Insert Alert to database.");
            } catch (InterruptedException e) {
                Log.error("Send mail Faild.", e);
            }
            // Log.infof("Send email to %s", data.name());
            // new Alert(alert.Level(), alert.message(), Instant.ofEpochMilli(data.create())).persistAndFlush();
        }
        Log.infof("Is OK.");
    }
}

接著部署至 Kubernetes,定義一個 Service 和 Deployment 資源。且 Pod 不定義 PreStopterminationGracePeriodSeconds,在不定義情況下來觀察其行為。


---
apiVersion: v1
kind: Service
metadata:
  annotations:
    app.quarkus.io/quarkus-version: 3.13.3
    app.quarkus.io/build-timestamp: 2024-08-29 - 07:46:57 +0000
  labels:
    app.kubernetes.io/name: gracefulshutdown
    app.kubernetes.io/version: day08
    app.kubernetes.io/managed-by: quarkus
  name: gracefulshutdown
spec:
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 8080
  selector:
    app.kubernetes.io/name: gracefulshutdown
    app.kubernetes.io/version: day08
  type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    app.quarkus.io/quarkus-version: 3.13.3
    app.quarkus.io/build-timestamp: 2024-08-29 - 07:46:57 +0000
  labels:
    app.kubernetes.io/name: gracefulshutdown
    app.kubernetes.io/version: day08
    app.kubernetes.io/managed-by: quarkus
  name: gracefulshutdown
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: gracefulshutdown
      app.kubernetes.io/version: day08
  template:
    metadata:
      annotations:
        app.quarkus.io/quarkus-version: 3.13.3
        app.quarkus.io/build-timestamp: 2024-08-29 - 07:46:57 +0000
      labels:
        app.kubernetes.io/managed-by: quarkus
        app.kubernetes.io/name: gracefulshutdown
        app.kubernetes.io/version: day08
    spec:
      containers:
        - env:
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          image: registry.hub.docker.com/cch0124/gracefulshutdown:day08
          imagePullPolicy: Always
          livenessProbe:
            failureThreshold: 3
            httpGet:
              path: /q/health/live
              port: 8080
              scheme: HTTP
            initialDelaySeconds: 5
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 10
          name: gracefulshutdown
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /q/health/ready
              port: 8080
              scheme: HTTP
            initialDelaySeconds: 5
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 10
          startupProbe:
            failureThreshold: 3
            httpGet:
              path: /q/health/started
              port: 8080
              scheme: HTTP
            initialDelaySeconds: 5
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 10

怎麼觀察 ? 這邊主要觀察 Pod 日誌,因此會透過 kubectl log 進行觀察。如下部署

day07$ kubectl apply -f kubernetes/kubernetes.yml

如果要看裝置訊息可以在瀏覽器輸入 http://localhost:9090/device/stream。但記得要使用 kubectl port-forward

查看日誌

$ kubectl logs -f --tail 100 gracefulshutdown-6c9c976df8-7szgd
2024-08-29 11:43:06,019 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Is OK.
2024-08-29 11:43:11,018 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) save completed.
2024-08-29 11:43:11,019 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) save completed.
2024-08-29 11:43:11,020 INFO  [org.cch.out.AlertConsumer] (executor-thread-2) Is OK.
2024-08-29 11:43:16,020 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) save completed.
2024-08-29 11:43:16,020 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) save completed.
2024-08-29 11:43:16,020 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) [Device] data: DeviceSimulation[name=madara-01, model=model05, volume=12.037659874378924, battery=8.608725828322894, create=1724931788015]
2024-08-29 11:43:16,021 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Sleep 5 s.
2024-08-29 11:43:18,932 INFO  [io.sma.rea.mes.mqt.ses.imp.MqttClientSessionImpl] (vert.x-eventloop-thread-1) Connection closed: <unknown>
...
2024-08-29 11:43:18,933 WARN  [com.arj.ats.arjuna] (Transaction Reaper Worker 0) ARJUNA012108: CheckedAction::check - atomic action 0:ffff0a2a011d:82e7:66d05eca:2 aborting with 1 threads active!
2024-08-29 11:43:18,933 WARN  [com.arj.ats.arjuna] (Transaction Reaper Worker 0) ARJUNA012121: TransactionReaper::doCancellations worker Thread[#144,Transaction Reaper Worker 0,5,main] successfully canceled TX 0:ffff0a2a011d:82e7:66d05eca:2
2024-08-29 11:43:21,021 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) save completed.
2024-08-29 11:43:21,021 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Send email to madara-01
2024-08-29 11:43:21,021 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Sleep 6 s.
2024-08-29 11:43:21,021 ERROR [io.qua.ver.cor.run.VertxCoreRecorder] (executor-thread-2) Uncaught exception received by Vert.x [Error Occurred After Shutdown]: java.util.concurrent.RejectedExecutionException: event executor terminated
        at io.netty.util.concurrent.SingleThreadEventExecutor.reject(SingleThreadEventExecutor.java:931)
        at io.netty.util.concurrent.SingleThreadEventExecutor.offerTask(SingleThreadEventExecutor.java:350)
        at io.netty.util.concurrent.SingleThreadEventExecutor.addTask(SingleThreadEventExecutor.java:343)
        at io.netty.util.concurrent.SingleThreadEventExecutor.execute(SingleThreadEventExecutor.java:833)
        ...

從 Log 來看有一個裝置進來如下,其 battary 是 8.608725828322894。

[Device] data: DeviceSimulation[name=madara-01, model=model05, volume=12.037659874378924, battery=8.608725828322894, create=1724931788015]

在他休息五秒要寄信時,透過 kubectl delete deployment 方式刪除服務。

day07$ kubectl delete deployments.apps gracefulshutdown 
deployment.apps "gracefulshutdown" deleted

刪除後,服務會立即中斷執行內容,並沒有將後續資料寫進資料庫。從後續的 Log 訊息並沒有發現 Insert Alert to database. 的日誌訊息。且進到 PostgreSQL 也確實沒有執行資料寫入動作

$ docker exec -it infra-postgres-1 /bin/bash
root@466dc12180c1:/# psql -U itachi
psql (15.8 (Debian 15.8-1.pgdg120+1))
Type "help" for help.

itachi=# \dt
itachi=# select * from alert
;
 battery | created | id | level | message
---------+---------+----+-------+---------
(0 rows)

terminationGracePeriodSeconds 整合

接著將寬限期拉大,即將 terminationGracePeriodSeconds 從預設 30 秒拉到 120 秒。新增欄位如下

apiVersion: apps/v1
kind: Deployment
metadata:
  ...
  name: gracefulshutdown
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: gracefulshutdown
      app.kubernetes.io/version: day08
  template:
    metadata:
      ...
    spec:
      terminationGracePeriodSeconds: 120
      ...

部署與驗證。

day07$ kubectl apply -f kubernetes/kubernetes-02.yml 

如下觀察,第一筆接收的裝置訊息 [Device] data: DeviceSimulation[name=naruto-01, model=model03, volume=36.21998712639848, battery=17.40290155338028, create=1724934464127] 有被寫入資料庫。第第二筆 [Device] data: DeviceSimulation[name=itachi-02, model=model02, volume=89.47304115578146, battery=7.619985232678439, create=1724934465127] 在寄信前 5 秒時段將其 Deployment 執行刪除資源。那在時間 2024-08-29 12:28:52 有完成寄信動作。

$ kubectl logs -f --tail 100 gracefulshutdown-b9d849fc8-xxh4j
...
2024-08-29 12:28:31,141 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) [Device] data: DeviceSimulation[name=naruto-01, model=model03, volume=36.21998712639848, battery=17.40290155338028, create=1724934464127]
2024-08-29 12:28:31,141 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Sleep 5 s.
2024-08-29 12:28:36,141 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) save completed.
2024-08-29 12:28:36,141 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Send email to naruto-01
2024-08-29 12:28:36,141 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Sleep 6 s.
2024-08-29 12:28:42,142 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Insert Alert to database.
2024-08-29 12:28:42,142 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Is OK.
2024-08-29 12:28:42,151 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) [Device] data: DeviceSimulation[name=naruto-01, model=model03, volume=36.21998712639848, battery=17.40290155338028, create=1724934464127]
2024-08-29 12:28:47,151 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) save completed.
2024-08-29 12:28:47,151 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) [Device] data: DeviceSimulation[name=itachi-02, model=model02, volume=89.47304115578146, battery=7.619985232678439, create=1724934465127]
2024-08-29 12:28:47,151 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Sleep 5 s.
2024-08-29 12:28:50,407 INFO  [io.sma.rea.mes.mqt.ses.imp.MqttClientSessionImpl] (vert.x-eventloop-thread-1) Connection closed: <unknown>
2024-08-29 12:28:50,408 WARN  [com.arj.ats.arjuna] (Transaction Reaper Worker 0) ARJUNA012108: CheckedAction::check - atomic action 0:ffff0a2a011e:9a27:66d06937:14 aborting with 1 threads active!
2024-08-29 12:28:50,408 WARN  [com.arj.ats.arjuna] (Transaction Reaper Worker 0) ARJUNA012121: TransactionReaper::doCancellations worker Thread[#139,Transaction Reaper Worker 0,5,main] successfully canceled TX 0:ffff0a2a011e:9a27:66d06937:14
2024-08-29 12:28:52,151 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) save completed.
2024-08-29 12:28:52,152 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Send email to itachi-02
2024-08-29 12:28:52,152 ERROR [io.qua.ver.cor.run.VertxCoreRecorder] (executor-thread-2) Uncaught exception received by Vert.x [Error Occurred After Shutdown]: java.util.concurrent.RejectedExecutionException: event executor terminated
...
2024-08-29 12:28:52,152 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Sleep 6 s.
2024-08-29 12:28:55,409 INFO  [io.qua.thread-pool] (Shutdown thread) Awaiting thread pool shutdown; 1 thread(s) running with 0 task(s) waiting
...
2024-08-29 12:28:58,153 INFO  [io.quarkus] (Shutdown thread) gracefulshutdown stopped in 7.748s

在上面日誌時間 2024-08-29 12:28:52 時有觸發睡眠 6s 的任務,但最後沒有觸發將資料插入置資料庫。被插入的資料只有 [Device] data: DeviceSimulation[name=naruto-01, model=model03, volume=36.21998712639848, battery=17.40290155338028, create=1724934464127]

itachi=# select * from alert
;
      battery       |          created           | id | level |    message
--------------------+----------------------------+----+-------+----------------
  17.40290155338028 | 2024-08-29 12:27:44.127+00 |  1 | LOW   | battery to Low
(2 rows)

到這邊其實看不出效果,對於此應用程式並沒有最後請求的動作因此不是很明顯。

terminationGracePeriodSeconds 與 preStop Hook 整合

從結果來看 Quarkus 沒有做一個完善的優雅關閉流程。接著在配置 preStop 進行觀察。在進行 terminationGracePeriodSeconds 有 30 秒讓 Pod 發送 SIGTERM 訊號時等待 30s。


apiVersion: apps/v1
kind: Deployment
metadata:
  ...
  name: gracefulshutdown
spec:
  replicas: 1
  selector:
    matchLabels:
      ...
  template:
    ...
    spec:
      terminationGracePeriodSeconds: 120
      containers:
        - env:
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          image: registry.hub.docker.com/cch0124/gracefulshutdown:day08
          lifecycle:
            preStop:
              exec:
                command: ["sleep","30"]

部署,

day07$ kubectl apply -f kubernetes/kubernetes-03.yml

老樣子觀察,在 2024-08-29 13:30:36 時間接收了 [Device] data: DeviceSimulation[name=madara-01, model=model05, volume=97.99759004198043, battery=5.578544203347069, create=1724938189276] 訊息,接著刪除 Pod 資源。緊接著發現,從 2024-08-29 13:30:05 到最後 2024-08-29 13:30:36 訊息過程中完美的利用了那 PreStop 的 30 秒進行一些後續操作。在這 30 秒過程中,它將裝置低於 30 的裝置進行寄信和發送郵件。不過範例的場景應是將與資料庫和 EMQX 連線進行中斷才對,避免繼續接收流量,但這只是一個驗證範例。

$ kubectl logs -f --tail 100 gracefulshutdown-b5c76b7dd-zpz8x
...
2024-08-29 13:30:00,281 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Is OK.
2024-08-29 13:30:00,290 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) [Device] data: DeviceSimulation[name=madara-01, model=model05, volume=97.99759004198043, battery=5.578544203347069, create=1724938189276]
2024-08-29 13:30:05,291 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) save completed.
2024-08-29 13:30:05,291 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Is OK.
2024-08-29 13:30:10,291 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) save completed.
2024-08-29 13:30:10,291 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) save completed.
2024-08-29 13:30:10,292 INFO  [org.cch.out.AlertConsumer] (executor-thread-2) Is OK.
2024-08-29 13:30:15,292 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) save completed.
2024-08-29 13:30:15,292 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) save completed.
2024-08-29 13:30:15,292 INFO  [org.cch.out.AlertConsumer] (executor-thread-2) Is OK.
2024-08-29 13:30:20,292 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) save completed.
2024-08-29 13:30:20,292 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) save completed.
2024-08-29 13:30:20,293 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) [Device] data: DeviceSimulation[name=itachi-02, model=model02, volume=6.2568560364611, battery=16.07017791819736, create=1724938193276]
2024-08-29 13:30:20,293 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Sleep 5 s.
2024-08-29 13:30:25,293 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) save completed.
2024-08-29 13:30:25,293 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Send email to itachi-02
2024-08-29 13:30:25,293 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Sleep 6 s.
2024-08-29 13:30:31,294 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Insert Alert to database.
2024-08-29 13:30:31,294 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Is OK.
2024-08-29 13:30:31,303 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) [Device] data: DeviceSimulation[name=itachi-02, model=model02, volume=6.2568560364611, battery=16.07017791819736, create=1724938193276]
2024-08-29 13:30:33,372 INFO  [io.sma.rea.mes.mqt.ses.imp.MqttClientSessionImpl] (vert.x-eventloop-thread-1) Connection closed: <unknown>
2024-08-29 13:30:36,303 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) save completed.
2024-08-29 13:30:36,303 ERROR [io.qua.mut.run.MutinyInfrastructure] (executor-thread-1) Mutiny had to drop the following exception [Error Occurred After Shutdown]: java.util.concurrent.RejectedExecutionException: event executor terminated
...
2024-08-29 13:30:36,303 INFO  [io.quarkus] (Shutdown thread) gracefulshutdown stopped in 2.933s

從上面來看基本上如果應用程式無法提供優雅關閉的流程,那可以藉由 PreStop 進行緩解讓應用程式來處理最後的請求。下表稍微做了整理

特性 terminationGracePeriodSeconds preStop hook
類型 時間 操作
觸發 Kubernetes 自動觸發 在 terminationGracePeriodSeconds 時間內觸發
目的 提供一個寬限期,指刪除 Pod 資源 執行特定的清理工作
關係 preStop hook 在 terminationGracePeriodSeconds 時間內執行 preStop hook 的執行時間影響 terminationGracePeriodSeconds 的效果

Quarkus 自身配置整合

如果應用程式本身有提供優雅關閉機制是最好,對於 Quarkus 確實存在此配置,如下,但預設是無啟用,更多配置資訊可參考官方解釋。

quarkus.shutdown.delay-enabled=true
quarkus.shutdown.delay=10s
quarkus.shutdown.timeout=30s

嘗試配置此三個機制給 Quarkus 應用程式本身,即在 env 欄位進行環境變數方式配置,最後 YAML 會長成。

apiVersion: apps/v1
kind: Deployment
metadata:
  ...
  name: gracefulshutdown
spec:
  replicas: 1
  selector:
    ...
  template:
    ...
    spec:
      terminationGracePeriodSeconds: 120
      containers:
        - env:
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: QUARKUS_SHUTDOWN_DELAY_ENABLED
              value: "true"
            - name: QUARKUS_SHUTDOWN_DELAY
              value: "30s"
            - name: QUARKUS_SHUTDOWN_TIMEOUT
              value: "60s"
          image: registry.hub.docker.com/cch0124/gracefulshutdown:day08.2
          lifecycle:
            preStop:
              exec:
                command: ["sleep","10"]
          imagePullPolicy: Always

同樣部署觀察

day07$ kubectl apply -f kubernetes/kubernetes-04.yml
$ kubectl logs -f --tail 100 gracefulshutdown-869d68bcc9-j4mk2
...
2024-08-29 16:32:37,312 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) save completed.
2024-08-29 16:32:37,313 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) save completed.
2024-08-29 16:32:37,313 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) [Device] data: DeviceSimulation[name=madara-01, model=model05, volume=74.074016201344, battery=24.746534393052187, create=1724949153308]
2024-08-29 16:32:37,313 INFO  [org.cch.out.AlertConsumer] (executor-thread-2) Sleep 5 s.
2024-08-29 16:32:42,313 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) save completed.
2024-08-29 16:32:42,313 INFO  [org.cch.out.AlertConsumer] (executor-thread-2) Send email to madara-01
2024-08-29 16:32:42,313 INFO  [org.cch.out.AlertConsumer] (executor-thread-2) Sleep 6 s.
2024-08-29 16:32:48,315 INFO  [org.cch.out.AlertConsumer] (executor-thread-2) Insert Alert to database.
2024-08-29 16:32:48,315 INFO  [org.cch.out.AlertConsumer] (executor-thread-2) Is OK.
2024-08-29 16:32:48,322 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) [Device] data: DeviceSimulation[name=madara-01, model=model05, volume=74.074016201344, battery=24.746534393052187, create=1724949153308]
2024-08-29 16:32:53,322 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) save completed.
2024-08-29 16:32:53,322 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Is OK.
2024-08-29 16:32:58,322 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) save completed.
2024-08-29 16:32:58,323 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) save completed.
2024-08-29 16:32:58,323 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) [Device] data: DeviceSimulation[name=madara-01, model=model05, volume=47.330818250200934, battery=19.749609483966967, create=1724949155308]
2024-08-29 16:32:58,323 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Sleep 5 s.
2024-08-29 16:33:00,529 INFO  [io.sma.health] (vert.x-eventloop-thread-5) SRHCK01001: Reporting health down status: {"status":"DOWN","checks":[{"name":"Database connections health check","status":"UP","data":{"<default>":"UP"}},{"name":"Graceful Shutdown","status":"DOWN"},{"name":"SmallRye Reactive Messaging - readiness check","status":"UP","data":{"deviceIn":"[OK]","deviceOut":"[OK]"}}]}
2024-08-29 16:33:03,323 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) save completed.
2024-08-29 16:33:03,323 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Send email to madara-01
2024-08-29 16:33:03,323 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Sleep 6 s.
2024-08-29 16:33:09,324 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Insert Alert to database.
2024-08-29 16:33:09,324 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Is OK.
2024-08-29 16:33:09,334 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) [Device] data: DeviceSimulation[name=madara-01, model=model05, volume=47.330818250200934, battery=19.749609483966967, create=1724949155308]
2024-08-29 16:33:10,529 INFO  [io.sma.health] (vert.x-eventloop-thread-8) SRHCK01001: Reporting health down status: {"status":"DOWN","checks":[{"name":"Database connections health check","status":"UP","data":{"<default>":"UP"}},{"name":"Graceful Shutdown","status":"DOWN"},{"name":"SmallRye Reactive Messaging - readiness check","status":"UP","data":{"deviceIn":"[OK]","deviceOut":"[OK]"}}]}
2024-08-29 16:33:14,334 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) save completed.
2024-08-29 16:33:14,334 INFO  [org.cch.out.AlertConsumer] (executor-thread-2) Is OK.
2024-08-29 16:33:19,334 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) save completed.
2024-08-29 16:33:19,335 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) save completed.
2024-08-29 16:33:19,335 INFO  [org.cch.out.AlertConsumer] (executor-thread-1) Is OK.
2024-08-29 16:33:20,529 INFO  [io.sma.health] (vert.x-eventloop-thread-7) SRHCK01001: Reporting health down status: {"status":"DOWN","checks":[{"name":"Database connections health check","status":"UP","data":{"<default>":"UP"}},{"name":"Graceful Shutdown","status":"DOWN"},{"name":"SmallRye Reactive Messaging - readiness check","status":"UP","data":{"deviceIn":"[OK]","deviceOut":"[OK]"}}]}
2024-08-29 16:33:24,335 INFO  [io.sma.rea.mes.mqt.ses.imp.MqttClientSessionImpl] (vert.x-eventloop-thread-1) Connection closed: <unknown>
2024-08-29 16:33:24,335 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-2) save completed.
2024-08-29 16:33:24,335 INFO  [org.cch.out.DeviceToPgDatabase] (executor-thread-1) save completed.
...

2024-08-29 16:33:24,337 INFO  [io.quarkus] (Shutdown thread) gracefulshutdown stopped in 30.004s

從上面結果來看,與上面類似,比較不一樣的是 quarkus.shutdown.delay 會讓 Pod 服務的 readiness 探針處於關閉狀態,如下紀錄,這預關閉期間,服務同樣還是會繼續照常工作,這使其它服務有時間檢測應用程式正在關閉並停止將流量路由到它。

Reporting health down status: {"status":"DOWN","checks":[{"name":"Database connections health check","status":"UP","data":{"<default>":"UP"}},{"name":"Graceful Shutdown","status":"DOWN"},{"name":"SmallRye Reactive Messaging - readiness check","status":"UP","data":{"deviceIn":"[OK]","deviceOut":"[OK]"}}]}

而最後的訊息 gracefulshutdown stopped in 30.004s 讓這關閉延長了約 30 秒,這不同於 Kubernetes 上的層級設定。

另外 quarkus.shutdown.delay-enabled 啟用時 quarkus.shutdown.delay 才會生效。且 quarkus.shutdown.delay-enabled 使建置期間的配置,也就是後期無法覆蓋。從結果來看,Quarkus 框架在支援優雅關閉的配置時,preStop 變成一個可選的配置。

確實最後 PostgreSQL 按照上面日誌來看有插入兩筆資料

itachi=# select * from alert
;
      battery       |          created           | id | level |    message
--------------------+----------------------------+----+-------+----------------
 24.746534393052187 | 2024-08-29 16:32:33.308+00 |  1 | LOW   | battery to Low
 19.749609483966967 | 2024-08-29 16:32:35.308+00 |  2 | LOW   | battery to Low
(2 rows)

下個章節,再進行細部比較。


上一篇
Pod 的最後一哩路
下一篇
Quarkus 最後一哩路,把它走完吧!
系列文
當 Quarkus 想要騎乘駱駝並用8腳章魚掌控舵手 31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言