查程式連網速度

之前家裡 wordpress 速度慢慢的,看了 PHP slow log ,發現是使用 libcurl 去外面抓資料時慢。後來用 SSH 連上去在命令列下使用 curl 試試,第一次會慢慢的,之後就比較正常了。

那,為什麼 curl 會慢?上網找了,有在 StackOverflow 上找到一個方法可以顯示 curl 在各階段處理時所花費的時間。先在 $HOME 下新增一個 .curlrc ,然後把下面內容貼進去

-w "dnslookup: %{time_namelookup} | connect: %{time_connect} | appconnect: %{time_appconnect} | pretransfer: %{time_pretransfer} | starttransfer: %{time_starttransfer} | total: %{time_total} | size: %{size_download}\n"

再去執行 curl ,輸出結果後面就會出現 curl 所花費的時間

dnslookup: 0.253 | connect: 0.264 | appconnect: 0.773 | pretransfer: 0.773 | starttransfer: 0.809 | total: 0.809 | size: 6665

那個時候,我連網速度慢的主因是 dnslookup 慢,所以就根據這點,去做調整。至於這個調整,就又是另外一個故事了。

如何寫 Git commit message

主要是看 How to Write a Git Commit Message 這篇文章的紀錄,這篇文章是 2014 年的文,我可能有看過,印象中之前有看過介紹原則跟工具的文章。之前的印象,第一行要明確、簡單,不要太長。有細項,從第三行寫起,用 markdown 語法。

這篇一開始先講為什麼,作者不囉唆,直接要你看自己的 git log –oneline 輸出,看自己覺得 OK 不 OK。所以可讀性很重要,可以很快的看懂,那麼就可以不用費心再去看裏面改了什麼。

主要有7個原則:

  1. Separate subject from body with a blank line :第一行寫主旨,第三行開始寫內容。
  2. Limit the subject line to 50 characters :主旨不要超過 50 個字元
  3. Capitalize the subject line :主旨的第一個字元大寫
  4. Do not end the subject line with a period :主旨不要有句點
  5. Use the imperative mood in the subject line :主旨要用祈使句,就動詞+名詞
  6. Wrap the body at 72 characters :內容的每行不要超過 72 的字元
  7. Use the body to explain what and why vs. how :內容要儘可能描述做了什麼、為什麼這樣做跟如何做。

Ansible – 版本判斷條件句

執行之前寫好的 Ansible 腳本,卻有錯誤,奇怪,明明之前是好的啊?看了錯誤訊息,發現是找不到 /proc/sys/net/ipv4/tcp_tw_recycle 這個檔案的關係。怎麼會沒有這個檔案呢?使用 SSH 連上主機去看,還真的是沒有,上網找了之後,發現是 Linux Kernel 在 4.12 以後移除掉這檔案了(連結)。

好吧,因為腳本還有機會在較低版本的 Linux kernel 使用,必須得使用條件式來處理。在 Ansible 腳本裡,可以用 when 來做條件判斷,但是要怎麼取得 Linux kernel 版本以及做條件判斷呢?在 StackOverflow 上看到這篇:How to compare kernel (or other) version numbers in Ansible

從這篇得知:

  1. 可以使用 ansible_kernel 就可以取得 Linux kernel 版本
  2. 可以使用 version_compare 來比較版本

所以下面的腳本就可以在 Linux kernel 是 4.12 以後的版本印出 “foo”

tasks:
  - name: Display "foo" if kernel > 4.12
    debug:
      msg: "foo"
      when: ansible_kernel | version_compare('4.12', '>')

太好了。可是再仔細看,執行時有 deprecated 的警告耶,說在之後會把 version_compare 拿掉。上 Ansible 網站看了 Ansible 的文件之後,做了調整,新的語法要使用 “is” 來判斷,然後用 version() 來取代 version_compare。

tasks:
  - name: Display "foo" if kernel > 4.12
    debug:
      msg: "foo"
      when: ansible_kernel is version('4.12', '>')

好,收工。

變數的命名

看這篇 The art of naming variables 的紀錄
變數命名的藝術,好吧,對非英語系國家來說,的確是有些難度。作者整理了一些慣例讓大家參考:

  1. Arrays :名詞字尾加上 s ,當複數。
  2. Boolean:變數用 is/has/can 開頭,例如 isOpen/hasWrite/canOpen,函數就用 check 開頭,例如 checkHasPermission()。
  3. Numbers:試著使用 min/max/total 來描述,例如 minBugs / maxPugs / totalFruits
  4. Functions:要有動詞跟名詞,例如 getUser() / calculateTotal() ;轉換的話,可以用 to,例如:toUppser() 。

我本來以為會有講 dict / list 的,但沒有,嗯,順手找了一下

  • List:可以考慮後綴就用 List,例如 namesList ,也有人把 list 擺在前面,例如 listOfNames
  • dict:有找,但沒有特定的慣例,參考 List 的命名作法應該是可以。然後有人這樣用 email_to_contact / ip_to_hostname

寫到這邊想起 Clean code 這本書有一章就是在講這個,直接看別人的讀書筆記/心得吧:

Cronitor

網址:https://cronitor.io

今天在 hacker news 上看到 crontab.guru,網址名稱挺不錯的,詳細介紹 crontab 怎麼用。正在想說怎麼會有人這麼佛心的建這網站時,就看到建立網站的是 cronitor.io。去看了 cronitor.io 以後,發現這個服務很有趣,是監控主機上的 cron job 用的。

一般 cron 的工作,只能透過 SMTP 發送結果,或者是自己去寫 wrapper ,把執行結果送到 slack, telegram 等服務。cronitor 就等同於是 wrapper 的角色,幫你執行指令,再把結果送到 cronitor 網站上,然後你可以在網站設定要通知誰。在網站上也可以去看 cron job 的執行歷程或者是知道到底有沒有被執行。

cronitor 這個工具不管是用網站介面或是 CLI,都需要先行安裝。安裝很簡單,就一個執行檔,下載以後,複製到 /usr/local/bin 就行了。(安裝說明,同時頁面也會提供你的 api-key)

tar xf cronitor-stable-linux-amd64.tgz
sudo cp cronitor /usr/local/bin
sudo cronitor configure --api-key <your-api-key>

你可以直接用網站介面,只是用網站介面,要先在介面上建立 cron job monitor ,然後再自己去改自家的 crontab,稍嫌麻煩。

用 CLI 比較方便,基本上用 sudo cronitor discover 就跑完了。sudo cronitor discover 會掃描你的 crontab,然後逐一詢問你 job 的名稱,然後再去網站上建立對應的 cron job monitor。這邊要注意的是,sudo cronitor discover 會自動幫你改 crontab ,也就是 root 的 crontab、/etc/cron.d 下的檔案都會幫你改掉。如果你不想這樣的話,得之後手動還原。目前網站雖然可以建立多個 cron job monitor,但目前只有一個 monitor 能運作,要用更多,得升級。收費的資訊在這裡:https://cronitor.io/subscribe

Bulma

介紹與教學

跟 Bootstrap 的差異與比較:https://bulma.io/alternative-to-bootstrap/

Django 生態圈已經有人寫 app 了 – django-bulma,支援 template 以及 form ,包的挺完整的。

AWS SES SMTP

前兩周碰到 GMAIL 很 GY 的問題,想說要不要去申請 MailGun ,後來想說,要另外申請服務挺麻煩(畢竟不是自家用),AWS 應該有這類服務吧。去 Google 以後,才發現自己之前有用過,只是全都忘光光了,這次要紀錄下來。這次的紀錄重點:

  1. 簡介
  2. 需要什麼?
  3. 如何移出 Sandbox?

AWS SES 是 AWS 的大規模電子郵件解決方案,可以用來寄發大量的電子郵件。他除了有提供 SMTP 設定之外,也可以直接使用程式來寄送。用 SMTP 設定方便的地方在於各個語言都有 SMTP 的函式庫可以用,所以設定填一填就可以寄了,不用額外再加函式庫。

要申請這個服務,要預先準備好網域,因為他是以網域為基礎。首先要新增網域,在進行新增網域的步驟時,步驟的說明會詳列出你該怎麼做來進行後續的驗證。這部份蠻簡單的,就只是去新增一個網域記錄,然後把 AWS 要求你填的資訊放進去就可以了。

在新增網域並進行驗證以後,就可以使用 SES SMTP 或是用程式去寄了。只是這時候是在 Sandbox 裡,有限制在的,不能寄太多信,寄件者跟收件者也都有限制。AWS Management console 也會提醒你,現在還在 Sandbox,如果需要提升額度或是可以寄送到外面,必須要提出申請 (有連結可以按),這邊就是照網頁說明去提出申請即可。提出申請時,AWS 會要求你回答幾個問題。這幾個問題主要是要確保 AWS 自身的立場,也就是當有人回報信件被濫用或退信時(抱怨),該怎麼去處理。

AWS 建議的作法就是要求你使用 AWS SNS ,當有退信或是抱怨時,讓 AWS 可以透過 AWS SNS 去通知你。AWS SNS 可以用郵件通知或是用 HTTP/HTTPS 去通知你的網站進行自動處理等等的。我後來是簡單的設定 AWS SNS,用郵件來通知我,等以後再來改成讓網站自動處理。

參考資料(來自AWS 文件):

NgRx

因為 NgRx 是用 Redux 的概念,所以先看 Redux

看完大致可以理解,就是 design pattern 裡講的 state pattern。大部份 Redux 例子都是搭配 React,看的還是霧煞煞,所以找 NgRx 搭配 Angular 的例子來看。

我覺得這三篇的例子蠻清楚的,很容易可以了解現有的 angular 碰到 ngrx 時,要怎麼結合。

原本 angular 的一個頁面是 component html 跟 component code ,現在加上 ngrx 以後,會使用 store 儲存狀態,寫 reducer 來處理狀態。當有事件觸發時,就使用 store.dispatch 去發送 action,reducer 在收到以後,會依據 action 來處理狀態,然後回傳狀態。這時候頁面會因為 binding ,而反映出新的狀態結果。

這三篇雖然清楚,但已經舊了,我在試驗時,就碰到兩個問題:

  1. 找不到 StoreModule.provideStore() 這個方法,這個已經改為 StoreModule.forRoot()
  2. Observable 找不到,要解決這個問題,除了得裝 rxjs 之外,還要裝 rxjs-compat 讓 rxjs 向前相容。

文章有提到 Redux DevTools 這個工具,可以從 Firefox addons/Chrome store NgRx 安裝,安裝以後,專案程式那邊也需要調整。調整的部份可以參考 @ngrx/store-devtools ,安裝好,修改 app.module.ts 之後,就可以使用了。使用的方式是先開啟專案的網址,然後再開 developer tools,這時會看到有個 Redux 分頁,試著觸發一些事件看看,這邊就會出現發送的 action 以及改變前後的狀態了。

CSRF is dead?

前幾天在 Hacker news 上看到 Scott Helme 寫的這篇 CSRF is (really) dead ,一直沒看。這兩天開始看,一開始 Scott Helme 先提,你應該先看這篇 Cross-Site Request Forgery is dead! ,再回頭來看。


我先看了第一段,心裡納悶這樣怎麼會有什麼危險呢?後來找了另外兩篇中文來看 (加快理解):

我蠻推第一篇 Huli 寫的文章,寫的很清楚。簡單的說,就是利用 cookie ,當別的網頁裡有嵌入對其他網頁的存取時,會因為 cookie 的關係而有存取權,如果網站沒有做適當的檢查,那麼使用者的資料就有可能遭到竊取或被錯誤的存取。這也是為什麼後來幾乎每套 web framework 都會有 CSRF token 的處理。

回頭來講,Scott Helme 會說 CSRF 死的原因很簡單,就是有了 SameSite cookie,在 2019 年6月以後幾乎各家都支援 SameSite cookie 了 – Can I use samesite cookie? 所以現在只要在 Set-Cookie 時,後面多加 SameSite=Strict 或 SameSite=Lax 就可以避免 CSRF 的風險了。

等到真正普及可能還要一到兩年的時間吧。

AWS S3/Glacier select

前幾天看 S3/Glacier FAQ 時,看到有 SELECT 這個功能,是去年推出的。S3/Glacier select  這功能是這樣子,你可以把 CSV/JSON/Apache Parquet 這幾種格式的檔案放到 S3/Glacier 上,然後就可以使用類似 SQL 的敘述來查詢檔案內容。

所以我們可以把不常使用的資料從資料庫移轉到 S3/Glacier 上,需要時,再使用 S3 SELECT 來查詢。這樣資料庫不需要一直擴充容量,放到 S3/Glacier 可以降低資料庫儲存的成本。

使用範例:

不過,網路上能找到的範例多半都是使用 CSV,那使用 JSON 又是如何呢?我試了以後,發現這個 JSON 格式不是我在 Python 用 json.dump() 傾印出來就搞定的。資料是陣列時,要針對每個元素去 dump,不可以是 [{}, {},…] 這樣,必須是 {} {} {} 這樣子,AWS API 才不會報錯 (參考:stackoverflow – amazon s3 – s3-select querying data on field name)。

import json

with open('output.json', 'wt') as fout:
  for obj in objs:
    json.dump(obj, fout, indent=2, ensure_ascii=True)
# 輸出結果
"""
{
  "id": 13930241}{
  "id": 13930240}
"""