Việc dev và test Cloudflare Worker dưới local là vô cùng cần thiết. Nó sẽ giúp developer tiết kiệm khá nhiều thời gian cho quá trình dev nhờ việc sử dụng một số tính năng của wrangler như hot reload, logging, v.v.
Gần đây Cloudflare đã hỗ trợ chạy Worker và các dịch vụ liên quan (KV, R2, D3, v.v.) trên máy local. Thay vì cần tạo Worker, KV, v.v. thay đổi code, deploy, tail log và test; thì đơn giản bạn chỉ cần chạy wrangler dev --local
.
Trong bài viết này, mình sẽ chia sẻ về Wrangler v3 và cách để dev/test Cloudflare Worker và Cloudflare KV mà không cần đẩy code lên CF.
Ngắn gọn về Wrangler v3
Ở phiên bản v2, Wrangler sử dụng Miniflare v2 để giả lập Cloudflare(CF) KV và các dịch vụ khác trên môi trường local. Điều này mang lại nhiều cải thiện so với bản v1: cho phép giả lập KV ở local và cho phép worker code có thể thêm, sửa, xoá dữ liệu trong local KV mà không cần deploy code lên production.
Tuy nhiên, vì Miniflare v2 là một tool được phát triển bởi bên thứ ba (sau này được CF mua lại); trong một số trường hợp, code dưới local và trên production có những hành vi không đồng nhất với nhau.
Đến phiên bản v3, Wrangler sử dụng Miniflare v3, và Workerd - môi trường runtime được CF sử dụng để chạy worker trên môi trường production. Điều này giúp cho việc chạy worker trên local gần như giống hoàn toàn môi trường production. Ngoài ra Wrangler v3 còn cung cấp thêm một số tính năng khác như:
- KV / D1 / R2 persistent - giúp cho data trên các service này trên local không bị mất đi sau mỗi lần stop wrangler.
- Hiệu năng tốt hơn Wrangler v2.
- Debugging, logging dễ dàng, cụ thể hơn.
- Các bạn có thể đọc thêm tại đây.
Ví dụ minh hoạ
Trong các phần tiếp theo của bài viết, mình sẽ chia sẻ cách sử dụng Wrangler để test ứng dụng Hello World (CF Worker + KV) trên môi trường local. Tính năng của ứng dụng này chỉ đơn giản là dịch từ hello world
sang ngôn ngữ mà người dùng đang sử dụng (detect thông qua http header Accept-Language
của request).
Chúng ta sẽ cùng thử cả hai cách sử dụng Worker + KV trên CF và Worker + KV giả lập dưới local để tiện so sánh sự khác biệt giữa hai cách này.
Tất cả code trong bài viết mình để ở đây:
https://github.com/phongvq/cloudflare-worker-helloworld
Bạn nào muốn thử tạo project từ đầu thì có thể làm theo hướng dẫn trong hướng dẫn này của Cloudflare.
Sử dụng KV + Worker trên Cloudflare
Trong phần này, chúng ta sẽ sử dụng wrangler dev --remote
để test worker + KV trên môi trường runtime thật của CF.
Đầu tiên, chúng ta sẽ clone sample code về.
$ git clone https://github.com/phongvq/cloudflare-worker-helloworld.git
cd cloudflare-worker-helloworld
Để sử dụng KV trên CF, chúng ta cần dùng lệnh wrangler
để tạo KV. Khi chạy CF Worker (thông qua Wrangler), người dùng bắt buộc phải sử dụng một KV riêng biệt, gọi là “preview KV”, để tránh “đụng chạm” vào dữ liệu trên production gây hậu quả nghiêm trọng. Vì vậy, chúng ta cần tạo KV “assets” và KV “assets preview”.
# Authenticate nếu cần
$ npx wrangler login
# Tạo KV 'assets'
$ npx wrangler kv namespace create assets
🌀 Creating namespace with title "miniflare-kv-langparser-assets"
✨ Success!
Add the following to your configuration file in your kv_namespaces array:
[[kv_namespaces]]
binding = "assets"
id = "babdd407ea874119874d54a39adedeec"
$ npx wrangler kv namespace create assets --preview
⛅️ wrangler 3.84.1 (update available 3.86.1)
-------------------------------------------------------
🌀 Creating namespace with title "miniflare-kv-langparser-assets_preview"
✨ Success!
Add the following to your configuration file in your kv_namespaces array:
[[kv_namespaces]]
binding = "assets"
preview_id = "de6667c02cc849f0b3ff5f35672126ac"
Thêm id của KV đã tạo vào phần config binding trong wrangler.toml
:
kv_namespaces = [
{ binding = "assets", id = "babdd407ea874119874d54a39adedeec", preview_id = "de6667c02cc849f0b3ff5f35672126ac" }
]
Upload dữ liệu trong hello-world.json
lên KV assets
(cả KV thật và KV preview):
$ npx wrangler kv key put hello-world.json --path hello-world.json --binding assets
⛅️ wrangler 3.84.1 (update available 3.86.1)
-------------------------------------------------------
Writing the contents of hello-world.json to the key "hello-world.json" on namespace babdd407ea874119874d54a39adedeec.
$ npx wrangler kv key put hello-world.json --path hello-world.json --binding assets --preview
⛅️ wrangler 3.84.1 (update available 3.86.1)
-------------------------------------------------------
Writing the contents of hello-world.json to the key "hello-world.json" on namespace de6667c02cc849f0b3ff5f35672126ac.
Các bạn có thể kiểm tra lại trên dashboard của CF:
Như vậy là phần data đã xong. Giờ đến phần chạy CF worker trên local, sử dụng KV đã tạo trên CF.
npx wranger --remote
sẽ đẩy code worker lên CF, chạy trực tiếp trên môi trường runtime của CF và sử dụng KV đã tạo trên đó.
> npx wrangler dev --remote
⛅️ wrangler 3.84.1 (update available 3.86.1)
-------------------------------------------------------
Your worker has access to the following bindings:
- KV Namespaces:
- assets: de6667c02cc849f0b3ff5f35672126ac
⎔ Starting remote preview...
[wrangler:inf] Ready on http://localhost:8787
Total Upload: 94.23 KiB / gzip: 21.64 KiB
Các bạn có thể thấy, wrangler sử dụng KV preview (assets: de6667c02cc849f0b3ff5f35672126ac
) để tránh động chạm tới dữ liệu thật (trong KV babdd407ea874119874d54a39adedeec
).
Test ứng dụng với curl
:
# tiếng Đức
$ curl 'http://localhost:8787/hello-world' -H 'Accept-Language: de-AT,de;q=0.5'
# tiếng Anh
$ curl 'http://localhost:8787/hello-world' -H 'Accept-Language: en-EN,en;q=0.5'
Ưu điểm:
wrangler dev --remote
chạy worker trên runtime của CF, tương tác với KV thật, mọi thứ giống môi trường chạy thật
Nhược điểm:
- Mỗi lần thay đổi code cần đợi wrangler upload code lên CF → người dùng phải đợi, trải nghiệm dev/test không được mượt mà lắm.
- Không thuận tiện cho việc xem log để debug - Mình cũng chưa biết tail log như thế nào,
wrangler tail
cũng không work, do Worker chưa được deploy lên CF. Xin các cao nhân chỉ giáo 🙏!
- Không có breakpoint cho debug,
console.log
không work! - Và thêm nhiều niềm đau khác.
Chạy KV + Worker trên môi trường local
Chính vì wrangler dev --remote
có nhiều bất cập, nên CF liên tục cải thiện workerd
, miniflare
, v.v. để việc dev/test CF Worker dưới local trơn tru hơn. Tất cả sẽ chạy trên local (máy tính của bạn):
- Data trong KV và các service khác sẽ được giả lập thông qua SQLite trên Local.
- Cloudflare Worker sẽ được chạy thông qua
workerd
(đằng sau là miniflare v3). - Tất cả mọi thứ đều được xử lý bởi Wrangler, người dùng chỉ cần thao tác ở mức high-level.
Giống như ở phần trên, chúng ta cũng cần cập nhật các config cần thiết trong wrangler.toml
.
Lưu ý: Trên lý thuyết, các bạn có thể sử dụng config giống hệt phần trên, chỉ cần thêm
--local
vào các lệnhwrangler
, mọi thứ vẫn sẽ hoạt động bình thường.
Tuy nhiên nếu làm vậy, mọi thông tin liên quan tới KV (name
,id
,preview_id
) sẽ được sử dụng lại, chỉ khác là data được đọc ghi từ máy local. Điều này rất dễ gây nhầm lẫn trong quá trình phát triển. Cá nhân mình thường chỉ định config dưới local ở trong một môi trường (Wrangler env) riêng.
Chúng ta cần cập nhật config của môi trường local trong wrangler.toml
như dưới đây:
# Tách biệt config ra môi trường riêng để tránh nhầm lẫn trong quá trình phát triển
[env.local]
kv_namespaces = [
{ binding = "assets", id = "local", preview_id = "local" }
]
Các bạn có thể chỉ định id
và preview_id
tuỳ ý, không cần chạy npx wrangler kv namespace create assets
(phần này docs của CF cũng không nói rõ, mình cũng đã mò mất một thời gian 🙏)
Sau đó insert data vào KV assets
ở local bằng lệnh:
$ npx wrangler kv key put hello-world.json --path hello-world.json --binding assets --preview false --local --env local
⛅️ wrangler 3.84.1 (update available 3.86.1)
-------------------------------------------------------
Writing the contents of hello-world.json to the key "hello-world.json" on namespace local.
$ npx wrangler kv key put hello-world.json --path hello-world.json --binding assets --preview --local --env local
⛅️ wrangler 3.84.1 (update available 3.86.1)
-------------------------------------------------------
Writing the contents of hello-world.json to the key "hello-world.json" on namespace local.
Có hai tham số được chỉ định trong các câu lệnh wrangler phía trên:
--local
: chạy worker và các dịch vụ liên quan trên máy local.--env local
: sử dụng các config (KV binding, v.v.) được chỉ định trong môi trường Wranglerlocal
(trong filewrangler.toml
)
Toàn bộ data sẽ được lưu vào thư mục .wrangler/state
(mặc định):
Dữ liệu local được quản lý bởi SQLite:
$ file .wrangler/state/v3/kv/miniflare-KVNamespaceObject/*
.wrangler/state/v3/kv/miniflare-KVNamespaceObject/2cccf226dfc814e7bbad3020e3117fcb058fe514bb0320c1ae72dfd971
2c89fb.sqlite: SQLite 3.x database, last written using SQLite version 3044000, writer version 2, read ve
rsion 2, file counter 1, database pages 1, cookie 0, schema 0, unknown 0 encoding, version-valid-for 1
.wrangler/state/v3/kv/miniflare-KVNamespaceObject/2cccf226dfc814e7bbad3020e3117fcb058fe514bb0320c1ae72dfd971
2c89fb.sqlite-shm: data
.wrangler/state/v3/kv/miniflare-KVNamespaceObject/2cccf226dfc814e7bbad3020e3117fcb058fe514bb0320c1ae72dfd971
2c89fb.sqlite-wal: SQLite Write-Ahead Log, version 3007000
Và cuối cùng là chạy worker và kiểm tra kết quả:
> npx wrangler dev --local --env local
⛅️ wrangler 3.84.1 (update available 3.86.1)
-------------------------------------------------------
Your worker has access to the following bindings:
- KV Namespaces:
- assets: local (local)
⎔ Starting local server...
[wrangler:inf] Ready on http://localhost:8787
Dữ liệu liên quan tới translation sẽ được đọc từ KV namespace local
, trên môi trường local
(thay vì KV có id dài loằng ngoằng trên CF như khi chạy wrangler dev --remote
).
Tadaaaa!
$ curl 'http://localhost:8787/hello-world' -H 'Accept-Language: en-EN,en;q=0.5'
<!DOCTYPE html>
<html>
<head>
<title>Hello World translation</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
% $ curl 'http://localhost:8787/hello-world' -H 'Accept-Language: de-AT,de;q=0.5'
<!DOCTYPE html>
<html>
<head>
<title>Hello World translation</title>
</head>
<body>
<h1>Hallo Welt!</h1>
</body>
</html>
Ưu điểm:
- Logs lỗi tường minh hơn - do chạy trực tiếp trên máy nên có thể xem được stacktrace rõ ràng.
- Hot reload tức thì, mỗi khi có code change.
- Có thể đặt debug point (điểm này mình chưa thử).
- Toàn bộ data quản lý trên máy local, không ảnh hưởng tới data chung của team trên CF. Ngoài ra, data được lưu trên disk nên persisted giữa các lần chạy worker.
Nhược điểm:
- Vì worker và các dịch vụ liên quan đều chạy theo kiểu simulated, nên khó tránh khỏi số ít trường hợp worker local chạy khác với worker trên CF. (trường hợp này cá nhân mình chưa gặp).
- Hiện tại CF chưa support local dev cho toàn bộ các service, và có một số hạn chế nhỏ khi thao tác với data của một số service trên local.
Kết luận
Bản thân mình thấy, từ khi CF support chạy worker và một số dịch vụ phổ biến trên local, việc dev/test worker trở nên dễ dàng hơn rất nhiều, không còn phải đẩy code lên môi trường trên CF rồi ngồi tail log như trước đây nữa.
Tuy nhiên nếu CF viết document cho phần này tường minh hơn một chút thì tuyệt vời!!
Docs của CF nói chung và của phần worker này nói riêng khá mập mờ, người dùng cần thu thập thông tin nhỏ lẻ từ nhiều phần khác nhau để có thể làm được điều mình muốn. Đổi lại thì chất lượng và tính dễ sử dụng của sản phẩm (cụ thể là CF worker) gần đây được cải thiện rất nhiều. Hy vọng thời gian tới sẽ có nhiều tính năng thú vị liên quan đến CF Worker và CF Page.
Cảm ơn các bạn đã đọc hết bài chia sẻ này của mình!
Peace ❤️
Một số bài viết của mình về chủ đề Cloudflare:
Bình luận