Idempotent Bash Script

看到「How to write idempotent Bash scripts」這篇,重點在講 Idempotence,這個詞是從數學上借來的,講重複操作的不動性:

An element x of a magma (M, •) is said to be idempotent if:

x • x = x.

If all elements are idempotent with respect to •, then • is called idempotent. The formula ∀x, x • x = x is called the idempotency law for •.

在 CS 領域也是一樣的概念:

Idempotence (UK: /ˌɪdɛmˈpoʊtəns/, US: /ˌaɪdəm-/) is the property of certain operations in mathematics and computer science whereby they can be applied multiple times without changing the result beyond the initial application.

而這篇講的是 Bash 上有些常見的行為要怎麼改成 Idempotence:

It happens a lot, you write a bash script and half way it exits due an error. You fix the error in your system and run the script again. But half of the steps in your scripts fail immediately because they were already applied to your system. To build resilient systems you need to write software that is idempotent.

一個常見的例子是 cron job 是否可以重複執行的問題。

如果 cron job 裡的程式都是 idempotent,那麼就不需要擔心重跑會因為前一隻 script 產生的環境而失敗,導致無限循環而需要人介入...

另外一個更進階的是同時有兩個 process 在執行同一個 script (可能在不同機器上),這也是要考慮的問題,不過這個問題在大多數情況下有各種 lock 系統可以協助避免,應該不是太大的問題...

macOS 打算移除 Perl/Python/Ruby

從 beta 版的 release note 可以看到 macOS 打算在 10.15 移除 PerlPythonRuby:「macOS 10.15 Beta Release Notes」。

Scripting language runtimes such as Python, Ruby, and Perl are included in macOS for compatibility with legacy software. Future versions of macOS won’t include scripting language runtimes by default, and might require you to install additional packages. If your software depends on scripting languages, it’s recommended that you bundle the runtime within the app. (49764202)

看起來會另外包一份出來... 不過這樣內建的工具就少了些,雖然 shell script 是 turing machine... :o

Internet 上的 3rd party js 的情況

Twitter 上看到這則:

裡面提到了「patrickhulce/third-party-web」的分析 (作者是從 HTTP Archive 的資料分析),裡面依照不同種類的 3rd party js (像是 ad,或是 social element,或是分析工具) 需要執行的時間,以及使用的站台數量。

Social 那邊意外看到 PIXNET 有上去,然後速度只比 Disqus 快一些,應該是沒有 optimize 的關係。

如果整體一起看的話 (總和花費時間),可以看到 Google 各項產品都在最前面,畢竟裡面每個項目都是被廣泛使用的。

用 link="preload" 提高下載的優先度

除了讓 browser 自己決定優先權外,在「Preload Scripts」這邊看到的技巧,可以跟 browser 說明哪些資源比較重要,請儘快先下載:

<link rel="preload" href="main.js" as="script">

Link rel=preload is useful for downloading any important resource more quickly, such as stylesheets that contain critical CSS, fonts that are used in important design elements, and hero images. It's especially important for scripts because they block page content from rendering and consume the most CPU during page load.

以作者的想法,這個技巧應該用在會卡住頁面呈現的部分,確保這些資源可以優先下載。

另外作者也提到了可以直接把這個資訊放到 HTTP header 裡面,理論上會更快:

Link: <main.js>; rel="preload"; as="script"

尤其是 sync script 應該會有幫助,建議可以跑 A/B test 看看效果:

We know that synchronous scripts block rendering, which makes the user experience feel slow. And we know that most scripts today are downloaded synchronously (rather than async). And yet only 1% of sites are using link rel=preload to download their scripts. If your site has any synchronous scripts, do an A/B test adding link rel=preload for them. It's likely this will be a win and help you create a more joyous experience for your users.

提供 Cheatsheet 的服務:cheat.sh

看到「chubin/cheat.sh」這個服務:

the only cheat sheet you need

他提供了 HTTP(S) 介面讓你存取 (透過 curl 或是其他的軟體),像是這樣的操作:

而且提供了 shell script 讓你可以更方便在 command line 下使用:

curl https://cht.sh/:cht.sh > ~/bin/cht.sh
chmod +x ~/bin/cht.sh

你可以把 cht.sh 換成其他你喜歡的名字,或是用 alias 方便操作...

用 mrtgutils-sensors 直接產生出 MRTG 用的溫度數字...

因為想要做另外一台機器的溫度資料,所以去查了一下有沒有現成的工具可以直接組完...

首先是在「How do I get the CPU temperature?」這邊查到 lm-sensors 這個套件,可以拉出一堆溫度資料 (不只 CPU 的),然後另外在「MRTG using script to grab data of sensors」這邊有人提到 mrtgutils-sensors 這個套件,可以直接將 sensors 的輸出結果轉成 MRTG 要的值,不需要自己寫 script...

把做好的東西丟在 https://home.gslin.org/mrtg/ 這邊,這樣可以觀察機器情況...

comm 的用法...

最近在 Twitter 上看到不少 shell 指令的說明,這則 tweet 是講 comm 這個指令:

1 是只有第一個檔案有的內容,2 是只有第二個檔案有的內容,而 3 是兩者都有的內容,而且檔案內容需要排序過。

當你 -1 時表示幹掉 1 的部份,-2 代表幹掉 2 的部份,-3 代表幹掉 3 的部份,然後可以疊起來用... 不過平常還是用 diff 比較多,每次看到 comm 的說明都是玩過再熟悉一下,然後就丟著 XD

合併 RRD 資料的工具

昨天把跑在 Raspberry Pi 上的 SmokePing 資料改用統一版本 (我在 GitHub 上公開的 smokeping-config.d 這個),但有些節點的 naming 改變了,所以會需要將資料整在一起。

在透過 Google 搜尋後,用的工具是「A very simple script to merge multiple RRD files, since none of those available seem to work.」這個,是一隻 Python 的程式。另外可以從程式碼裡面看到他使用了 rrdtool 這個 CLI 工具 (SmokePing 用了 RRD 格式儲存資料),所以使用這隻程式前需要先安裝 rrdtool 這個套件:

$ sudo apt install rrdtool

接下來就是照說明來轉換。由於 rrdtool 這隻程式沒有對 filename 做特殊處理 (i.e. 把 - 當作 stdin),所以會使用到 /dev/stdin 這種特殊方式來當作 input:

./simple-rrd-merge.py input-a.rrd input-b.rrd | rrdtool restore /dev/stdin output.rrd

當然,要記得先把 SmokePing 停掉再跑會比較好 XD

生出的 RRD 檔案再覆蓋回去 (我是先備份起來,以免有意外...),然後再把 SmokePing 跑起來就可以了。

以 Google Chrome 的情況分析各種 script 的利弊與使用時機

在「Script Scheduling in Chrome」這邊看到關於各種 <script> 的時機,主要是以 Google Chrome 環境為主。作者在文章裡面有提到「Scheduling Scripts Intuitively and Performantly」這份文件,並且將最上面的表格取出來,光是這張表就給了不少想法:

文件裡面有更多細節可以看,而且有些討論其實是在思考要怎麼修改 spec 讓網站更容易設 script priority...

針對 Ubuntu 16.04 + PPPoE 時,OpenNTPD 的 -s 不會在啟動時直接校正的問題 workaround...

發現機器時間跟標準時間差了 40 秒左右,結果有些服務因為會看雙方時間,就不讓我跑... XDDD

找問題找了半天,發現開機後 ntpdate 會回報找不到伺服器,看起來是網路根本就還沒通就跑起來了:

Jan 25 13:10:30 home ntpdate[757]: name server cannot be used: Temporary failure in name resolution (-3)
Jan 25 13:10:30 home ntpdate[1171]: name server cannot be used: Temporary failure in name resolution (-3)
Jan 25 13:10:30 home ntpdate[1347]: name server cannot be used: Temporary failure in name resolution (-3)
Jan 25 13:10:30 home ntpdate[1410]: name server cannot be used: Temporary failure in name resolution (-3)

而理論上 與 openntpd 加上 -s 也會做類似的事情,所以這邊就在 /etc/default/openntpd 先加上 -s,讓他開機時強制對時一次,看看能不能解... 結果也是一樣在網路還沒通的時候就跑起來而失敗了:

Jan 25 13:10:45 home ntpd[1457]: no reply received in time, skipping initial time setting

由於這台機器是 HiNet 的 PPPoE,看起來有可能是某些條件沒寫好,造成執行順序不對... 所以就找個 workaround 來解決 @_@

後來找的方法是直接到 /etc/ppp/ip-up.d/ 下放一個 script 實作 workaround,直接在 PPPoE 連上後重跑 openntpd,然後用 hwclock 寫回主機裡,下次開機的時間就會比較準一些了:

#!/bin/sh -e

/usr/sbin/service openntpd restart
/sbin/hwclock -w

不過實際上還是要找看看要怎麼把 PPPoE 掛到 networking 那層行為裡面...