拆解比較:為什麼有時候 AWS CLI create-invalidation 清不掉 Amazon CloudFront 快取

Post Title Image (Photo by Wilhelm Gunkel on Unsplash)

簡介

自從將自己的 blog 從 GitHub Pages 搬到 Amazon S3 + Amazon CloudFront 之後,整個佈署時間、網頁載入時間都縮短許多。

就算是類似 Ernest PKM 個人知識系統 工作流程 這種超級長文類型,網頁載入時間也能有 DOMContentLoaded < 650 ms、 Load < 2.5 s 的表現。佈署時間大幅度地從 GitHub Pages build 平均約需要 10~13 分鐘,縮短為沒有改動圖片時小於 1 分鐘。

但也因此發現下一個問題,CDN 快取週期也要自己管理與取捨了。

身為「偷懶為進步之母」流派,在自己的 blog 直接用萬用字元 * 來清除我的 Amazon CloudFront distribution 裡面的 cache 應該也是個夠偷懶的做法(吧 :p

那大家有沒有比較過以下的情況?哪一種 paths 的給值,才能真的建立一個 invalidation 來清除 Amazon CloudFront distribution 裡面的 cache 呢?

  • (A) aws cloudfront create-invalidation --distribution-id {dist_id} --paths /*
  • (B) aws cloudfront create-invalidation --distribution-id {dist_id} --paths '/*'
  • (C) aws cloudfront create-invalidation --distribution-id {dist_id} --paths *
  • (D) aws cloudfront create-invalidation --distribution-id {dist_id} --paths '*'

可能會因為作業系統和所在的 SHELL 環境而有所不同,大家可以未看先猜看看。

以下紀錄我在 macOS 13 + zsh + AWS CLI 2.11 的結果,我的情況是要選擇 (B)。

❌ (A) /* with slash, without quote

SHELL 會幫忙多做事情:請參考 Shell expansion 文中的「3.4.9. File name expansion」。所以底下執行結果會看到有 16 個 Path Items。但這些都不存在於我的 Amazon CloudFront distribution 之中,所以每次都有成功建立 CloudFront invalidation,但是沒有對應到想要清掉的 path,所以我就算執行了這行 AWS CLI 指令,還是沒有更新我的 blog 文章快取,繼續看到舊版本文章內容。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
❯ aws cloudfront create-invalidation --distribution-id {dist_id} --paths /*
{
    "Location": "https://cloudfront.amazonaws.com/2020-05-31/distribution/{dist_id}/invalidation/IEFW9PJ2I78V8D7KL3X90S8D7N",
    "Invalidation": {
        "Id": "IEFW9PJ2I78V8D7KL3X90S8D7N",
        "Status": "InProgress",
        "CreateTime": "",
        "InvalidationBatch": {
            "Paths": {
                "Quantity": 16,
                "Items": [
                    "/Applications",
                    "/home",
                    "/Volumes",
                    "/private",
                    "/Users",
                    "/bin",
                    "/sbin",
                    "/var",
                    "/dev",
                    "/usr",
                    "/etc",
                    "/opt",
                    "/System",
                    "/Library",
                    "/cores",
                    "/tmp"
                ]
            },
            "CallerReference": "cli-1685975853-185479"
        }
    }
}

✅ (B) /* with slash, with quote

可以看到 Path Item 變成 1 個了,而且就是我想要的偷懶方法 /*

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
❯ aws cloudfront create-invalidation --distribution-id {dist_id} --paths '/*'
{
    "Location": "https://cloudfront.amazonaws.com/2020-05-31/distribution/{dist_id}/invalidation/IPBL9DUBVBJ39DIJ7EHE6CS9K",
    "Invalidation": {
        "Id": "IPBL9DUBVBJ39DIJ7EHE6CS9K",
        "Status": "InProgress",
        "CreateTime": "",
        "InvalidationBatch": {
            "Paths": {
                "Quantity": 1,
                "Items": [
                    "/*"
                ]
            },
            "CallerReference": "cli-1685977774-963591"
        }
    }
}

❌ (C) * without slash, without quote

在 AWS Management Console 手動操作 CloudFront invalidation 的時候,AWS Management Console 會貼心地幫忙加上開頭的 slash。但是其實 CloudFront API 的設計是要吃到 /* 才能動作的,所以只輸入 * 給 API 是過不了的。

1
2
3
❯ aws cloudfront create-invalidation --distribution-id {dist_id} --paths *

An error occurred (InvalidArgument) when calling the CreateInvalidation operation: Your request contains one or more invalid invalidation paths.

❌ (D) * without slash, with quote

1
2
3
❯ aws cloudfront create-invalidation --distribution-id {dist_id} --paths '*'

An error occurred (InvalidArgument) when calling the CreateInvalidation operation: Your request contains one or more invalid invalidation paths.

參考資料

Loading comments…