Bỏ qua để đến nội dung

Sự kiện thời gian thực (SignalR)

Các cập nhật trực tiếp đi qua một hub SignalR tại /hub/realtime. Xác thực dùng cùng JWT như REST API, truyền dưới dạng ?access_token=<jwt> (hoặc một header Authorization).

Các luồng tần số cao là opt-in theo từng nhóm, chỉ tham gia khi một màn hình tiêu thụ được mount và tự động tham gia lại khi kết nối lại:

NhómMangĐược tiêu thụ bởi
sensorsCác lô đọc cảm biến trực tiếpRealtime Monitor
predictionsCác lô dự đoán mớiBiểu đồ bảng điều khiển
logsToàn bộ luồng log (mọi mức)Chỉ trang LogViewer
alertsChỉ các mục log Warning/ErrorChuông thông báo, toàn ứng dụng

Nhóm alerts tồn tại để các cảnh báo nổi lên khắp nơi mà không phải stream toàn bộ “vòi rồng” logs tới mọi bảng điều khiển.

Hub phát ra mười hai sự kiện, và bảng dưới đây liệt kê đầy đủ. Tên trường đến ở dạng camelCase: giao thức hub JSON áp dụng chính sách camelCase của ASP.NET Core lên các record payload phía server. Mọi timestamp là Unix epoch mili-giây trừ khi có ghi chú khác.

Sự kiệnGửi tớiPayload
ConnectedChỉ client vừa kết nốiconnectionId, timestamp
SensorReadingBatchNhóm sensorsticks — các tick cảm biến được gộp từ lần flush trước (hình dạng bên dưới)
NewPredictionBatchNhóm predictionspredictions — các bản ghi dự đoán được gộp từ lần flush trước (hình dạng bên dưới)
LogEntryNhóm logsid, timestamp (chuỗi ISO-8601), source, level, message, logger (nullable), correlationId (nullable; cùng một id trên mọi dòng của một tick, từ lần đọc đầu vào đến từng lần ghi đầu ra), inputDatasourceId, inputDatasourceName, outputDatasourceId, outputDatasourceName (đều nullable; có giá trị khi dòng thuộc về một tick suy luận — tên là tên tại thời điểm ghi dòng, id giữ nguyên khi đổi tên)
AlertLogEntryNhóm alertsCùng hình dạng với LogEntry, chỉ mang các mục mức Warning và Error
InferenceStateChangedMọi clientstate ∈ idle · ready · running, activeInputDatasourceId (nullable), loadedModelId (nullable), loadedModelVersion (nullable), timestamp — phát ra ở mọi chuyển tiếp vòng đời
InferenceFaultedMọi clientreason, datasourceId (nullable), timestamp, severity (mặc định error), code (nullable) — đồng thời hiện banner lỗi chặn
HealthMetricsUpdateMọi clientstatus, timestamp, gpu (đối tượng nullable), cpu, memory, storage (đối tượng nullable), uptimeSeconds (engine suy luận), backendUptimeSeconds, engineRestartCount, lastEngineRestartAt (nullable) (hình dạng lồng nhau ở bên dưới)
ModelActivatedMọi clientmodelId, version, inputShape, outputShape, fileSizeMb
ModelUploadProgressMọi clientmodelId, version, phase, isError, errorMessage (nullable)
ModelUploadFailedMọi clientmodelId, version, reason
OutputWriteFailedMọi clientdatasourceId, reason, code (nullable), severity (warning), timestamp, count — gộp theo từng sink: lần thất bại đầu tiên cảnh báo tức thì, sau đó nhiều nhất một sự kiện tiếp theo mỗi cửa sổ 30 giây, với count lần lặp được gộp vào

Tên sự kiện chính là tên phương thức trên interface hub client phía server, nên các tên ở trên là tên trên dây (wire name) mà client đăng ký nghe.

Mỗi phần tử của SensorReadingBatch.ticks là một tick — mọi giá trị kênh được đóng dấu tại một thời điểm sinh dữ liệu duy nhất:

TrườngÝ nghĩa
timestampThời điểm sinh dữ liệu cho cả tick
valuesMột giá trị cho mỗi kênh; values[i] là kênh chỉ số i

HealthMetricsUpdate lồng các đối tượng sau:

Đối tượngTrường
gpuutilization, memoryUsedMb, memoryTotalMb, memoryUsagePercent, temperatureCelsius — cả đối tượng là null trên host không có GPU, và trước lần poll thành công đầu tiên
gpu.memoryKindshared (Jetson: GPU dùng RAM hệ thống, nên các trường bộ nhớ GPU lặp lại số đo của host), dedicated (VRAM riêng), hoặc null khi không rõ
cpuusagePercent, temperatureCelsius (null khi host không có cảm biến nhiệt CPU)
memoryusagePercent, usedMb, totalMb — RAM của host
memory swapswapUsedMb, swapTotalMb, swapUsagePercent — null khi host không có swap hoặc không đọc được
memory.inferenceusedMb, limitMb, usagePercent, source (nullable) — bộ nhớ container suy luận so với giới hạn mà tại đó container bị dừng (RAM cộng swap); cả đối tượng là null khi container không có giới hạn hoặc không đọc được
storagetotalGb, usedGb, freeGb, usagePercent, databaseMb — mỗi trường đều nullable; cả đối tượng là null khi không đọc được ổ đĩa

Các trường memoryKind, swap và inference là bổ sung: engine suy luận báo cáo chúng, nên với engine cũ hơn chúng đến dưới dạng null và bảng điều khiển hiển thị là không được báo cáo. storage do chính backend đo.

Mỗi phần tử của NewPredictionBatch.predictions là một bản ghi dự đoán:

TrườngÝ nghĩa
requestIdĐịnh danh của yêu cầu suy luận đã tạo ra bản ghi
predictionsĐầu ra mô hình, một giá trị cho mỗi kênh đầu ra
confidenceScoresMột giá trị độ tin cậy cho mỗi kênh đầu ra
modelIdMô hình đã tạo ra dự đoán
inferenceTimeMsThời gian thực thi mô hình
timestamp, windowStartTimestamp, windowEndTimestamp, emittedAtXem mục kế tiếp

Một dự đoán mô tả một cửa sổ đầu vào trong quá khứ. Mọi timestamp đều là Unix epoch mili-giây từ một đồng hồ — backend đóng dấu mỗi mẫu một lần tại thời điểm đọc, và giá trị đó được truyền qua pipeline, không bao giờ được sinh lại:

TrườngÝ nghĩa
windowStartTimestampMẫu đầu vào cũ nhất trong cửa sổ
windowEndTimestampMẫu đầu vào mới nhất — thời điểm “tính đến” mà dự đoán có hiệu lực
timestampPhản chiếu windowEndTimestamp (tương thích)
emittedAtThời gian đồng hồ backend lúc phát — emittedAt − windowEndTimestamp ≈ độ trễ end-to-end

Trên bảng điều khiển, vệt dự đoán trễ hơn vệt cảm biến một cách rõ ràng đúng bằng độ trễ pipeline thực. Khoảng cách đó là một tín hiệu vận hành có chủ đích, không phải lỗi render.

Consumer chậm không bao giờ làm chậm suy luận: các broadcast tới bảng điều khiển là fire-and-forget, và các sự kiện tới một client không theo kịp sẽ bị bỏ và đếm (/api/inference/backpressure). Các sự kiện đáng thông báo được khử trùng lặp và giới hạn tốc độ để chuông vẫn hữu ích — xem Thông báo.