---
# System prepended metadata

title: Connect 交接文件
tags: [aira]

---

---
tags: aira
---
## 說明
1. .env 可以參考 58 的 `/opt/aira/airaConnect`。
2. [Postman 設定檔](https://drive.google.com/file/d/1eyA-30UuXBvWWtuw392ethbUz0WxB77E/view?usp=sharing)。

## 專案清單
| 客戶 | 專案 | 前一手 |
| -------- | -------- | -------- |
| 禾順     | [Dockerized Juifeng](https://github.com/airaTaiwan/dockerized_juifeng)     | - |
| 禾順     | [先前的 Connect](https://github.com/airaTaiwan/juifeng-connect)     | [玉清](https://github.com/e234xp/airaConnect) |
| 禾順     | [先前的 Connect - Data Receiver](https://github.com/airaTaiwan/juifeng-data-receiver)     | [玉清](https://github.com/e234xp/airaDataReceiver) |
| 禾順     | [監控 + 發通知](https://github.com/airaTaiwan/airaEventHandler)     | - |
| 禾順     | [OpenData 及水位爬蟲](https://github.com/airaTaiwan/aira-task-scheduler)     | - |
| 第一電阻 | [Connect 產機具／環控假資料的工具](https://github.com/airaTaiwan/new_aira_connect_helper) | - |
| 第一電阻 | [Connect](https://github.com/airaTaiwan/aira-connect) | - |

## 交接情形
### 禾順
- [x] 1. Dockerized Juifeng
    - [x] 確保拉得到專案
    - [x] 知道要把匯出的 docker images 擺在什麼位置
        - [x] `bin/connect` - api 及 websockets
        - [x] `bin/data-receiver` - 收 mqtt/tcp 資料
        - [x] `bin/task-scheduler` - 氣象、水位爬蟲
        - [x] `bin/event-handler` - 監控、發通知
    - [x] 確保知道怎麼更新 images／重啟 service
        - [x] `make load`
        - [x] `make up`
    - [ ] 確保知道如何查看日誌
        #### event-handler
        ```bash
        docker compose logs -f event-handler
        ```
        #### task-scheduler
        ```bash
        docker compose logs -f task-scheduler
        ```
        #### connect
        ```bash
        docker compose logs -f connect
        ```
        #### data-receiver
        ```bash
        docker compose logs -f data-receiver
        ```
    - [x] 確保知道怎麼架設到新主機上
        #### 壓縮
        ```bash
        cd /opt/aira
        tar --exclude=mongo -zcvf airaConnect.tar.gz airaConnect
        ```
        ### 解壓縮
        ```bash
        # 在目標主機上
        cd /opt/aira
        tar -zxvf airaConnect.tar.gz airaConnect
        ```
    - [x] 確保改得到設定檔
        ```.env
        # 觀測站 ID，例如「C0R590」
        OPEN_DATA_WEATHER_STATION_ID=
        # 案場所在的縣市，例如「屏東縣」
        OPEN_DATA_COUNTY=
        # 案場所在的鄉鎮市區，例如「里港鄉」
        OPEN_DATA_TOWN=
        # 潮汐觀測站位置，例如「臺南市安平區」
        WALRUS_MONITORING_STATION_LOCATION=
        # （禾順專用）水位觀測站 ID，例如「11891,11892」，允許多筆用逗點隔開。
        JUIFENG_MONITORING_DEVICES=
        # （禾順專用）取得水位觀測站資料用的 Acess Token
        JUIFENG_ACCESS_TOKEN=
        # 發送 LINE 通知用的 Acess Token（跟 Azure 或 Jack 要）
        LINE_NOTIFY_ACCESS_TOKEN=
        ```
- [x] 2. 先前的 Connect / Data Receiver
    - [x] 確保拉得到專案
    - [x] 確保專案可以修改並且修改會生效
        - [x] `npm run bundle`
        - [x] `npm run build`
        - [x] `npm run save`
- [x] 3. Open Data 及水位爬蟲
    - [x] 確保拉得到專案
    - [x] 確保專案可以修改並且修改會生效
        - [x] `npm run compile:watch`
        - [x] `npm run bundle`
        - [x] `npm run build`
        - [x] `npm run save`
- [x] 4. 監控 & 發報
    - [x] 確保拉得到專案
    - [x] 確保專案可以修改並且修改會生效
        - [x] `npm run compile:watch`
        - [x] `npm run bundle`
        - [x] `npm run build`
        - [x] `npm run save`

### 第一電阻
- [x] 1. Connect
    - [x] 確保拉得到專案
    - [x] 確保本機可以運行
        - [x] 交接 .env
        - [x] 在本機開放 API Endpoint 但使用 192.168.10.58 作為資料中心
    - [x] 確保可以用 Postman 測試
    - [x] 確保專案可以修改並且修改會生效
        - [x] `npm run watch`
        - [x] `npm run api`
        - [x] `npm run build`
        - [x] `npm run deploy`
    - [x] 確保知道如何確認基礎設施狀態並查看工作日誌
        - [x] [RabbitMQ](http://192.168.10.58:15672/)
            ![image](https://hackmd.io/_uploads/BJPGU7_TC.png)
            - aira
            - Az123456
        - [x] Mongo
        - [x] ETCD
            - [x] 按 key-value 儲存內容，但目前沒有好的介面可以看它儲存的內容，只能從 logs 看有沒有正常運作。
                ```bash
                docker compose logs -f renewingetcd
                ```
        - [x] 查看工作日誌的方式
            - [x] DEBUG 環境變數
                - [x] 可以先在 .env 裡設定一個統一的 `DEBUG=*,-etcd,-express*,-follow-redirects*`，並且 `docker compose up -d --force-recreate` 能看到最完整的 logs。
                - [x] 也可以個別 service 各自設定 `DEBUG=` 環境變數（寫在 environment）。
            - [x] dispatcher.yaml
                從 dispatcher 可以看到從 iot 收到的資料以及各種常駐資料（例如設備狀態）同步的情形。
                ```bash
                docker compose -f dispatcher.yaml logs -f
                ```
            - [x] cron.yaml
                從 cron 可以看排程（例如抓取氣象資料）的執行情形。
                ```bash
                docker compose -f cron.yaml logs -f
                ```
            - [x] http.yaml
                從 http 可以看 api 及 websocket 的執行情形。
                #### api
                ```bash
                docker compose -f http.yaml logs -f api
                ```
                #### websocket
                ```bash
                docker compose -f http.yaml logs -f ws
                ```
            - [x] docker-compose.yaml
                可以看各 workers 的執行情形。
                #### 更新機具狀態
                ```bash
                docker compose logs -f machinerymessagereceived
                ```
                #### 監控並發送通知
                ```bash
                docker compose logs -f monitoringdeviceState
                ```
    - [x] Known Issues
        - [x] 1. etcdserver: mvcc: database space exceeded
        #### 狀態
        已經調整設定檔還在觀察中（上一次調整時間是 2024-09-18 10點）。
        
        #### 具體影響
        1. 監控發通知時如果因為 etcd 無法更新，監控的 worker 就無法拉到新的裝置狀態並根據新的狀態來判別並且發送通知。
        2. 氣象爬蟲會無法顯示最新拉取到的資料。
            #### 目前的處置方式
            根據[這份文件](https://www.zhaowenyu.com/etcd-doc/ops/data-space-manage.html)，在 crontab 中加入了（`crontab -e`）：
            ```bash
            */15 * * * * cd /opt/aira/persistentStorage && make compact && make defrag && make disarm
            ```
            應該只有 Connect 會遇到這個問題。原因是因為每次更新 key value etcd 都會多存一個版本，而 Connect 會頻繁的更新裝置的狀態。
            #### 備援方案
            如果還是出現這個問題，請執行：
            ```bash
            cd /opt/aira/persistentStorage && docker compose up -d etcd --force-recreate # 重開 etcd
            cd /opt/aira/airaConnect && docker compose -f dispatcher.yaml up -d --force-recreate # 重開 dispatcher
            ```
        - [x] 2. Matt 反饋說 Connect，第一電阻的儀表板閒置一段時間後回去看會變得很卡（其實從跳板 ssh 連線到主機也會卡頓）。
            #### 狀態
            目前觀察到主機 CPU 滿低的，但記憶體被 mongo 用盡了。猜測是因為沒有限制 mongo 的資源使用量導致記憶體被 mongo 用盡。
            #### 處理狀態
            先對 mongo 的記憶體採取限制，正在觀察中（從 2024-09-06 直到 2024-09-18 沒再發生）。
        - [x] 3. Connect 目前還跑著一個需要很久時間的 migration（預估會跑到 10 月中旬）。
            #### 查看執行情形
            ```bash
            docker compose -f cron.yaml logs -f
            ```
            #### 重新執行
            已執行過的會被忽略，但是百分比是按剩餘未執行過的紀錄計算，所以還是會從 0.0% 開始。
            ```bash
            docker compose -f cron.yaml up -d --force-recreate
            ```
- [x] 2. 產假資料的工具
    - [x] 確保知道如何在 58 重新編譯
        ```bash
        # 先覆蓋 lib
        cd /home/aira/桌面/new_aira_connect_helper
        flutter build linux
        ```
    - [x] 確保知道如何使用產假資料的工具
        位置在 `/home/aira/桌面/new_aira_connect_helper/build/linux/x64/release/new_aira_connect_helper`
        
## 驗證運作狀態
1. top (shift p)
![image](https://hackmd.io/_uploads/rkl0SocpC.png)
    - %Cpu(s)
    - avail Mem
2. 看 Queue 有沒有塞車
![image](https://hackmd.io/_uploads/SkLyLo5T0.png)
3. df -h 看磁碟用量
![image](https://hackmd.io/_uploads/HJffUi9TR.png)
4. 看 migration 有沒有在執行
    ![image](https://hackmd.io/_uploads/BywS8s5TR.png)
    ```bash
    docker compose -f transporter.yaml logs -f
    ```



## 其他文件
1. [如何解決 make 指令 .ONESHELL 沒有作用的問題](https://hackmd.io/an4yDG7BQrS7u58mC_ALng)。
2. [啟用 license 的方法](https://hackmd.io/UVKjnLP_RceglPu4uOLo2w)。
3. 計算平均執行時間的方法：
    #### 倒出 logs
    ```bash
    docker compose logs > docker-compose.log
    ```
    #### 計算平均執行時間
    ```bash
    node parse-log.js # docker compose .logs 要擺在專案根目錄下
    ```
4. 打包 persistentStorage 的方法
    #### 壓縮
    ```bash
    tar --exclude=data -zcvf persistentStorage.tar.gz persistentStorage
    ```
    #### 解壓縮
    ```bash
    # cd /opt/aira
    tar -zxvf persistentStorage.tar.gz
    ```
5. 打包 airaConnect 的方法
    #### 壓縮
    ```bash
    tar -zcvf airaConnect.tar.gz airaConnect
    ```
    #### 解壓縮
    ```bash
    # cd /opt/aira
    tar -zxvf airaConnect.tar.gz
    ```

## 備註
### 關於設計上的一些問題
#### 1. 關於 API 欄位命名的問題
請找 Matt。

#### 2. 關於 Connect API URI 命名的問題
請找玉清。

#### 3. 關於 Connection Profiles、通訊設備、匣道器、燈號之間錯綜複雜的關係
請找 Matt、Azure。

#### 4. 為什麼用 traefik：
因為想要 api 也可以開 replica（nginx 的 streaming + reverse proxy 會設定得比較複雜）。

#### 5. 為什麼用 nginx 放靜態檔案（而不是讓 express 直接吐）：
可以設定靜態檔案的快取並且讓讀取動作由多個 workers 去幫忙做。

#### 6. 為什麼要在 Service 外再掛一層 reverse proxy (traefik、nginx)？
- 譬如憑證，可以統一由 traefik 或 nginx 管理，就不用每一個 app 都要知道怎麼處理 SSL 的事情，憑證也比較好自動更新。
- 幫忙作 Load Balance，可以讓一個 endpoint 背後有多個 replicas 幫忙服務，增加吞吐量。

#### 7. 為什麼選用 etcd 而不是 redis？
- redis 每次讀取都會重拉一次資料，這個拉的過程還是有 latency。
- etcd 可以做到一旦有更新才拉取資料，可以大幅減少拉取的次數。且拉取完的資料是直接存放在記憶體，從記憶體取出的話速度會快很多。

#### 8. replica 越高使用的 cpu/cores... 資源就越多嗎？
一個 replica 相當於一個獨立的 container，會對應到作業系統裡的一個 process。由於每個 process 的記憶體空間是隔開的，replica 越高一個的最直接影響就是記憶體開銷上升。
每個 process 在某個時間點會從作業系統分配到 time slice，process 越多(replica 越高)或是 threads 越多的時候，就越多人在這個池子裡面等。

當某個 process 有無限迴圈時，等到 time slice 到了，作業系統會觸發中斷機制，讓它把 cpu 讓給別人。如果它長期佔用 cpu，作業系統可能會降低它拿 time slice 的優先級，甚至強制停止它。

意思是在 cpu 還有剩餘的時候，繼續加 replica 是有助於有效使用資源的。

但過多 process 時，會導致每個 process 都只能做一下下事情，cpu 就讓出去，東西切來切去也需要時間成本（而且其實這個成本很昂貴），反而讓事情變得更做不完。

### Mongo Collections 介紹
#### administrators
管理員帳號、密碼、角色、email 等。
> 注意：
> 1. 現在仍沿襲原有的程式碼以明文儲存密碼（應該要作 oneway hash 並且撒鹽）。
> 2. 目前密碼也跟著 XOR Cipher 一起打進 token（最好從 token 的內容裡拔掉）。
![image](https://hackmd.io/_uploads/HkZ_lGdTR.png)

#### alertPolicies
![image](https://hackmd.io/_uploads/SJSVbMO60.png)
監控規則、通知時間、通知方式等。
> 注意：
> 應該再拆分 Notifier（譬如 smtp server, username, password）、Preset(subject, body)、Schedule 幾個部分，讓 Notifier 可以重用。

#### alerts
![image](https://hackmd.io/_uploads/ryZxzz_6C.png)
dashboard 看到的系統通知會存在這邊。
websocket 會按這邊寫入的情形發送通知到前端。

#### communicationEquipments
![image](https://hackmd.io/_uploads/SyqmGzdaR.png)
匣道器和通訊設備管理。

#### deviceGroups
![image](https://hackmd.io/_uploads/Bky8fM_6A.png)
設備群組存管理。

#### deviceTypes
![image](https://hackmd.io/_uploads/rJbvMM_T0.png)
設備類型管理

#### devices
![image](https://hackmd.io/_uploads/SkAdfGu60.png)
設備管理。機具、環控等都存在同一張表。

#### environmentalMonitoringPannelConfigurations
![image](https://hackmd.io/_uploads/SJdpMz_pR.png)
環控儀表板管理。
似乎只有禾順的專案有用到。

#### *DailyStats - 
![image](https://hackmd.io/_uploads/BJDfXGd60.png)
環控日報表（以濕度為例）。

values 儲存數值的最高、最低、平均值。
stats 儲存燈號持續時間及出現次數。

#### *MonthlyStats
![image](https://hackmd.io/_uploads/rk7Y7MuTR.png)
 環控月報表（以濕度為例）。
 
values 儲存數值的最高、最低、平均值。
stats 儲存燈號持續時間及出現次數。
migratings 為 migration 執行過程中用來計算狀態是否持續的欄位，在 migration 完成後即可忽略。
events 為日常運行時計算狀態是否持續的欄位。

#### *StateSnapshots
![image](https://hackmd.io/_uploads/SJHsmGO6C.png)
環控設備狀態。

單一設備於某個時間區間的狀態。當燈號改變／隔夜時，會新開一筆狀態紀錄。

#### *Stats
舊的環控報表，因為儲存到最後很可能會發生超過 mongo 單一 document 儲存大小上限的問題，已棄用。

#### licenses
![image](https://hackmd.io/_uploads/BJxD4MOa0.png)
licenses 管理。

#### machineryDailyStats
![image](https://hackmd.io/_uploads/HyZIBMdpA.png)

lights 當天的燈號。
stats 燈號的持續時間及出現次數。

#### machineryMonthlyStats
![image](https://hackmd.io/_uploads/SJDWLG_pA.png)
stats 燈號的持續時間及出現次數。

#### machineryStateSnapshots
機具於某一個時間點的狀態。
![image](https://hackmd.io/_uploads/r1hz8zdTC.png)

#### machineryStats
舊的機具報表，因為儲存到最後很可能會發生超過 mongo 單一 document 儲存大小上限的問題，已棄用。

#### maps
![image](https://hackmd.io/_uploads/BkP98fd60.png)
地圖管理。

順序用 index 存。

#### notifications
![image](https://hackmd.io/_uploads/HyQ3LMOpR.png)

儲存要發送的／已發送的通知及發送的結果。

#### machineryMessages, sevenInOneMessages, temperatureAndHumidityMessages
![image](https://hackmd.io/_uploads/S13zDMd6A.png)
各設備收到的 Raw Data。

#### workJournals
日誌管理。