在上一章節理解優雅關閉(Gracefule shutdown)相關概念,此章節會透過 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 不定義 PreStop
和 terminationGracePeriodSeconds
,在不定義情況下來觀察其行為。
---
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
從預設 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)
到這邊其實看不出效果,對於此應用程式並沒有最後請求的動作因此不是很明顯。
從結果來看 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.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)
下個章節,再進行細部比較。