Deno Queues
(deno.com)- Deno Queues là hàng đợi phân tán serverless chạy trên Deno KV, cho phép chuyển các tác vụ tốn thời gian sang xử lý bất đồng bộ hoặc lên lịch thực thi trong tương lai
- Nhà phát triển chỉ cần đưa thông điệp vào bằng
.enqueue()và xử lý bằng.listenQueue(), không cần thiết lập hay duy trì hạ tầng hàng đợi riêng - Trên môi trường cục bộ, nó dùng SQLite; trên Deno Deploy, nó dùng FoundationDB, và Deploy sẽ khởi chạy V8 isolate theo yêu cầu tại thời điểm xử lý thông điệp
- Cơ chế chuyển phát là at-least-once delivery, nên trong các tình huống lỗi hoặc retry, cùng một thông điệp có thể được xử lý nhiều lần
- Không có phí riêng cho hàng đợi, nhưng enqueue được tính là ghi KV, còn nhận thông điệp được tính là ghi KV và một request Deno Deploy, nên cần cân nhắc cả xử lý trùng lặp lẫn cấu trúc chi phí
Deno Queues đảm nhiệm việc gì
- Deno Queues là tính năng hàng đợi dựa trên Deno KV, cho phép chuyển một phần xử lý của ứng dụng sang tác vụ bất đồng bộ hoặc lên lịch công việc để chạy sau
- Deno hướng tới việc giảm bớt các bước thiết lập lặp đi lặp lại và cấu hình hạ tầng trong phát triển phần mềm đám mây, đồng thời cung cấp các thành phần nền tảng để nhà phát triển có thể thiết kế, cải tiến và phát hành nhanh hơn
- Deno KV là tùy chọn lưu trữ bền vững dựa trên FoundationDB và hiện đang ở trạng thái open beta
- Queues cung cấp khả năng nhắn tin có thể mở rộng và quản lý xử lý nền trên Deno KV
API cơ bản và cách hoạt động
- Deno Queues có hai API cốt lõi
.enqueue(): đưa thông điệp mới vào hàng đợi để chuyển ngay lập tức hoặc tại một thời điểm trong tương lai.listenQueue(): dùng làm handler để nhận và xử lý thông điệp mới từ hàng đợi
- Luồng cơ bản là mở KV bằng
Deno.openKv(), gửi thông điệp Slack tronglistenQueue, và chỉ địnhenqueuevới{ delay: 60000 }để thông điệp được xử lý sau 60 giây - Tùy theo môi trường chạy mà nơi lưu trữ sẽ khác nhau
- Khi chạy cục bộ thì dùng SQLite
- Khi chạy trên Deno Deploy thì dùng FoundationDB
- Trên Deno Deploy, khi đến thời điểm có thể xử lý thông điệp, hệ thống sẽ khởi chạy V8 isolate theo yêu cầu và dispatch thông điệp
- Mã ứng dụng chỉ cần nhận thông điệp mới trong handler
listenQueue, còn phần quản lý thực thi còn lại do Deno Deploy đảm nhiệm
Bảo đảm chuyển phát và retry
- Deno Queues bảo đảm at-least-once delivery
- Phần lớn thông điệp được enqueue sẽ chỉ gọi handler
listenQueuemột lần, nhưng trong một số tình huống lỗi, cùng handler có thể bị gọi nhiều lần để bảo đảm chuyển phát - Vì vậy ứng dụng cần xử lý thông điệp trùng lặp một cách an toàn
- Nếu handler
listenQueueném ra exception, runtime sẽ tự động retry lời gọi - Việc retry sẽ tiếp tục cho đến khi thành công hoặc đạt tới số lần retry tối đa; hiện giá trị mặc định tối đa là 5 lần
- Thông điệp đạt tới số lần retry tối đa sẽ bị xóa
Dùng cùng KV atomic transaction
- Deno Queues có thể kết hợp với KV atomic transactions
- Nếu enqueue thông điệp như một phần của KV transaction, thông điệp chỉ được đưa vào hàng đợi khi toàn bộ transaction thành công
- Luồng ví dụ là kiểm tra và cập nhật số dư của Bob và Liz, sau đó enqueue thông điệp thông báo cho cả hai
- Dùng
check(bob, liz)để kiểm tra trạng thái - Giảm số dư của Bob và tăng số dư của Liz
- Dùng
enqueueđể thêm thông điệp thông báo lần lượt cho Liz và Bob - Chỉ khi
commit()thành công thì toàn bộ thay đổi và enqueue mới được áp dụng
- Dùng
- Có thể cập nhật trạng thái Deno KV ngay bên trong handler
listenQueue - Nếu muốn bảo đảm cập nhật cho từng thông điệp chỉ diễn ra một lần, có thể xây dựng luồng chống xử lý trùng lặp bằng cách lưu rồi xóa nonce
- Khi enqueue thì lưu kèm nonce
- Khi xử lý, nếu không có nonce thì trả về ngay
- Khi xử lý thành công thì xóa nonce và đồng thời cập nhật bộ đếm cùng trạng thái số dư
Các trường hợp sử dụng phù hợp cho hàng đợi
- Hàng đợi giúp server chuyển xử lý bất đồng bộ và lên lịch tác vụ tương lai, nên hữu ích cho việc mở rộng ứng dụng
-
Thông báo email theo lịch
- Khi một tác vụ do người dùng khởi tạo mất nhiều thời gian hoặc không cần chờ phản hồi hoàn tất, có thể chuyển tác vụ đó vào hàng đợi để giữ cho server hoặc ứng dụng vẫn phản hồi tốt
- Trong ví dụ, thông điệp
welcome_emailđược enqueue ngay lập tức, còn thông điệpsurvey_emailđược chạy trễ với{ delay: 259200000 }
-
Xử lý webhook đáng tin cậy
- Nếu không xử lý ngay request webhook mà đưa nó vào hàng đợi, có thể tách phần phản hồi khỏi phần xử lý thực tế
- Kết hợp Oak và Queues để khi nhận request POST
/webhook, nội dung request sẽ được đưa vào hàng đợi và trả về HTTP 200 - Việc xử lý webhook thực tế sẽ được thực hiện bất đồng bộ trong
listenQueuebằngprocessWebHook
-
Bot Slack·Discord
- Queues cũng có thể dùng để xây dựng bot Discord hoặc Slack
- Ví dụ ứng dụng Slack reminder là trường hợp tạo ứng dụng nhắc nhở Slack đơn giản bằng Deno Queues
- Ví dụ bot Discord dùng Deno Queues để tạo giveaway và cho phép người dùng tham gia chỉ với một cú nhấp
- Có thể xem thêm nhiều ví dụ sử dụng hàng đợi tại docs.deno.com
Cách tính phí
- Deno Queues không có hạng mục tính phí chuyên biệt riêng
- Chi phí được tính dựa trên thao tác Deno KV và request Deno Deploy
- Enqueue thông điệp: mỗi thao tác enqueue tương ứng với 1 lần ghi KV
- Nhận thông điệp: mỗi thông điệp được nhận sẽ phát sinh 1 lần ghi KV và 1 lần tính phí request
- Đây là cấu trúc chỉ tính phí cho các thao tác thực sự được sử dụng
Tài liệu và lộ trình
- Tài liệu liên quan và tham chiếu API
- Để xây dựng web app và server có khả năng mở rộng, cần có cấu hình chuyển các tác vụ nền sang hàng đợi, nhưng cách làm trước đây thường có nhiều bước thiết lập
- Deno Queues được tích hợp sẵn trong runtime và hoạt động trên hạ tầng Deno Deploy, cho phép sử dụng hàng đợi phân tán serverless chỉ với vài dòng mã
- Deno Queues được đặt cùng với Deno KV, web standards APIs, npm, all-in-one modern tooling như những thành phần nhằm giúp phát triển web trở nên đơn giản và hiệu quả hơn
- Có thể gửi phản hồi và yêu cầu tính năng qua Discord hoặc deploy_feedback issues
1 bình luận
Ý kiến trên Hacker News
Tôi vừa đào sâu vào bên trong phiên bản SQLite cục bộ và ghi chú lại: https://til.simonwillison.net/deno/deno-kv#user-content-deno...
Phần thú vị nhất có lẽ là schema dùng cho tính năng này:
CREATE TABLE queue ( ts integer not null, id text not null, data blob not null, backoff_schedule text not null, keys_if_undelivered blob not null, primary key (ts, id) );CREATE TABLE queue_running( deadline integer not null, id text not null, data blob not null, backoff_schedule text not null, keys_if_undelivered blob not null, primary key (deadline, id) );CREATE INDEX kv_expiration_ms_idx on kv (expiration_ms);Chẳng phải index được thiết kế chính là để dùng cho những việc như vậy à?
Khá mới mẻ nhưng cũng hơi bất an. Tất nhiên họ phải thương mại hóa, nhưng không nhất thiết phải theo cách hoàn toàn đóng; với lớp mở rộng, có lẽ họ cũng có thể dùng các giấy phép khác như BSL hoặc PolyForm
Mình cho rằng hướng Deno đang nhắm tới ở đây khá hướng đến tương lai
Năm nay tôi mới bắt đầu dùng Go, và một phần của ngôn ngữ này rất giống C. Ngoài những điểm khác với C, chẳng hạn nhờ garbage collection mà có thể trả về từ hàm một giá trị trông như con trỏ được cấp phát trên stack, các tính năng tích hợp sẵn như
map[string]stringcũng được đưa vào rất tự nhiên. Nếu tạo một ngôn ngữ mới sau năm 2023 mà không có cú pháp tích hợp để xử lý kiểu map thì tôi thấy gần như khó chấp nhậnVì vậy, việc một hệ sinh thái xoay quanh web server có các thư viện, và có lẽ một ngày nào đó cả cú pháp ngôn ngữ, cho những primitive mà chúng ta thường dùng là điều có vẻ hợp lý. Tôi không nhớ nổi dự án gần đây nhất về web server phân tán mà lại không có key-value store để làm cache, cơ chế khóa, thậm chí cả queue tạm thời. Hệ thống phân tán không có key-value store lờ mờ giống một ngôn ngữ lập trình không có kiểu map, và đó thực sự là một công nghệ kiểu dao đa năng Thụy Sĩ
Vấn đề tiềm ẩn là Deno đang đi con đường này một mình. Hiện khó chắc liệu các tính năng mới mà Deno thêm vào có được cung cấp trên các nền tảng cạnh tranh hay không, và dù API được công bố mã nguồn mở, nó vẫn nằm trong namespace
Deno, nên tôi không biết liệu khi muốn đổi từ FoundationDB sang Redis trên AWS thì nó có cứ thế hoạt động hay khôngVì vậy tôi có cảm giác muốn tránh Deno. Cú pháp và các tính năng được phơi ra thật sự hấp dẫn, nhưng tôi lo rằng sau khi đã phụ thuộc vào nó, để có thể triển khai lên nhiều hạ tầng cloud khác nhau tôi sẽ phải đại phẫu code. Nhiều khách hàng yêu cầu điều này. Ví dụ một ngày nào đó tôi muốn bán cho Oracle hay Salesforce, nhưng họ yêu cầu chạy on-premises, thì việc làm sao áp dụng key-value store mà phía đó dùng được cho khớp với tính năng package
Denosẽ đổ lên đầu tôiĐây là con dao hai lưỡi. Deno có thể thành công trong việc thúc đẩy tầm nhìn này đến một nhóm rộng hơn, nhưng trong thời gian tới có lẽ tôi vẫn sẽ nhìn nhận một cách thận trọng
Tôi đã dùng thử nhẹ
kv-connect-kit, một triển khai giao thức này bằng TypeScript thuần, và nó cung cấp API KV client trong bất kỳ JavaScript runtime nào. Bao gồm cả Cloudflare Workers, nơi hoàn toàn không có namespace DenoGitHub: https://github.com/skymethod/kv-connect-kit / npm: https://www.npmjs.com/package/kv-connect-kit / deno/x: https://deno.land/x/kv_connect_kit / demo: https://keyspace.deno.dev/
Giao thức có vẻ hoạt động đúng như mô tả, và việc viết backend khác cũng trông khá đơn giản
Ngành công nghệ đã tiến khá xa để thoát khỏi các stack khóa chặt vào nhà cung cấp, nhưng điều này lại gợi nhớ đến những thời kỳ đó
Tôi không thấy khác biệt thực chất giữa việc
Deno.KVđược đưa vào như một phần của runtime và việc thêmimport KVở đầu file. Cách sau có thể import ở bất cứ nơi nào bạn muốn, dù là Deno hay nơi khácVà khả năng nhóm Deno cung cấp binding cho các ngôn ngữ khác ngoài ngôn ngữ của họ là bao nhiêu? Nếu Google bắt đầu đưa các primitive chỉ dành cho Google Cloud vào Go một cách native, bạn có gọi đó là hướng đến tương lai không?
Đồng thời, self-hosting cũng phải ngang bằng hoặc tốt hơn các bên dẫn đầu ngành. Một con đường khác là từ bỏ self-hosting và cung cấp một giải pháp multi-cloud với biên lợi nhuận mỏng đặt trên các adapter của đối tác hosting. Khi đó Deno không cần trực tiếp cạnh tranh với tư cách nhà cung cấp hosting nữa
Tôi thấy đây không hẳn là hướng đến tương lai mà gần với việc kiếm tiền từ Deno dưới dạng SaaS hơn. Đó là xu hướng mà ngày nay ai trong thế giới JavaScript cũng làm với sản phẩm “cloud”: gắn framework vào rồi bán lại AWS. Vì vậy nên nó mới có bảng giá
Nếu KV của Deno phụ thuộc vào FoundationDB, khả năng họ tích cực tạo adapter cho các cơ sở dữ liệu khác cũng có vẻ thấp. Thay đổi công nghệ cơ sở dữ liệu luôn là chuyện lớn, vì mỗi loại có mục đích sử dụng và đặc tính hiệu năng khác nhau
GC allowing one to return what look like stack allocated pointers from functionstheo tôi không hẳn là nhờ garbage collection mà là nhờ escape analysis và SSALập luận rằng “để tận dụng hạ tầng public cloud thì phải lục lọi boilerplate code và cấu hình phức tạp, tiêu tốn nhiều thời gian và năng lượng của lập trình viên” không thuyết phục lắm
Rốt cuộc, chúng ta đang xây dựng hạ tầng cần phải ổn định. Bỏ 30 phút để cấu hình hàng đợi SQS, một công nghệ đã được kiểm chứng, không có vẻ tệ hơn việc hoàn toàn tin vào một hàng đợi đồ chơi mà Deno tạo ra “trên SQLite / FoundationDB”. Chi phí cấu hình 30 phút và “trải nghiệm lập trình viên” tốt hơn có thật sự đáng để chấp nhận rủi ro đó không? Ngay từ đầu thì bạn cấu hình hàng đợi thường xuyên đến mức nào?
Với tư cách lập trình viên làm vì sở thích, tôi không hay dùng các nhà cung cấp lớn như AWS hay Google, vì chúng trông khá phức tạp. Nếu đã quen thì có thể cũng không tệ đến vậy
Ngoài ra, tôi muốn mỗi dự án là một repository độc lập trên GitHub. Lý tưởng nhất là bất kỳ ai khác cũng có thể dễ dàng dựng web app dưới một domain riêng như một web app độc lập của họ. Vì tôi không muốn chịu trách nhiệm cả dữ liệu của người khác
Điều này phần nào giống use case của Sandstorm. Hướng dẫn cài đặt kiểu “thử nghiệm cục bộ, còn nếu muốn dùng thật thì hãy tạo tài khoản Deno Deploy” nghe khá hợp lý
Nếu ai đó cung cấp một thư viện tương đương cho cloud thì chắc chắn sẽ có người dùng. Với Deno, có vẻ họ đang tìm các vấn đề chung mà lập trình viên trong hệ sinh thái của họ gặp phải, rồi đóng gói một giải pháp ổn để xử lý
Nếu dùng workflow engine trừu tượng hóa hàng đợi, bạn có thể “chỉ viết code” mà không phải quản lý task, lịch, trạng thái, retry
https://www.inngest.com/blog/how-durable-workflow-engines-wo...
Tuy nhiên, tôi là tác giả của workflow engine nên có thiên kiến
Theo kinh nghiệm trước đây khi xử lý “ngữ nghĩa giao ít nhất một lần” và “code của người dùng”, người dùng không hiểu đúng về giao ít nhất một lần
Ngay khi message được gửi lại, phàn nàn của người dùng và sự cố sẽ ập đến
Tôi nghĩ hoặc là làm được điều gần như bất khả thi và phát minh ra ngữ nghĩa giao đúng một lần, hoặc là phải luôn gửi lại 0,1% tất cả message để người dùng không thể phụ thuộc vào việc chúng chỉ được giao một lần
Hiện tôi đang dùng Deno Deploy, và với dự án làm một mình thì hiệu năng rất tốt và thật sự đơn giản
Từ góc nhìn của người từng phát triển trên AWS trong một đội lớn, tôi rất mừng khi thấy xu hướng thoát khỏi sự phức tạp để có thể dễ dàng triển khai mà không phải nghĩ về cấu hình. DNS cũng rất đơn giản và chứng chỉ SSL tự động thì thật sự tuyệt. Tôi hoàn toàn không phàn nàn gì về hướng đi của sản phẩm này, và cũng mong chờ roadmap của họ
Nếu tôi không bỏ sót gì thì có vẻ mỗi instance
Deno.openKv()chỉ có một hàng đợiỞ phiên bản cục bộ, có thể tạo nhiều hàng đợi bằng cách gọi
Deno.openKv("db-2.db")với một đường dẫn file SQLite khác nhau mỗi lần, nhưng so với một nhu cầu khá phổ biến thì overhead có vẻ lớnCó lẽ đây là phong cách kiến trúc của Deno. Khi xây dựng ứng dụng phức tạp bằng Deno, họ kỳ vọng một cấu trúc kiểu microservice, trong đó nhiều script hoạt động cùng nhau và mỗi script có KV store cùng hàng đợi riêng của nó chăng?
Một trong các core developer đã xác nhận trên Discord: https://discord.com/channels/684898665143206084/115671428253...
Trích dẫn: “Đúng vậy. Hiện tại chỉ hỗ trợ một hàng đợi duy nhất. Tuy nhiên, có thể multiplex nhiều loại message trong một hàng đợi duy nhất.”
Giá cả thế nào?
Tôi từng nghĩ Deno là một dạng thay thế cho Node.js, hay tôi đang bỏ sót gì? Có thể dùng cái này cục bộ hoặc self-host miễn phí không?
Vì “Queues are built on Deno KV”, lời giải thích là ở cục bộ thì dùng SQLite, còn trên Deno Deploy thì dùng FoundationDB để có độ sẵn sàng và throughput tối đa
Tôi đã viết thêm một chút về pattern này ở đây: https://til.simonwillison.net/deno/deno-kv
Nếu các developer có đọc, tôi nghĩ với tính tiện dụng KV hiện rất tốt, phần kiểm soát truy cập có thể gây đau đầu về sau
Tôi tò mò không biết giải pháp chỉ là “tự triển khai trong không gian người dùng và đừng tạo bug”, hay đã có kế hoạch gì chưa
Hỗ trợ Jupyter gần đây và tính năng hàng đợi lần này rất đáng mong đợi. Chúng thật sự rất hay
Nhưng tôi không nghĩ mình sẽ viết server bằng Deno rồi đưa lên production trên server của mình. Tôi không thích serverless
Mô hình kinh doanh của Deno và Bun được xây dựng quanh serverless, tức Deno Deploy. Và Deno Deploy lại là một runtime khác
Điều đó thể hiện rõ ở KV và hàng đợi. Khi chạy cục bộ hoặc self-host, bạn có một phiên bản chỉ vừa đủ chạy được, đặt trên các công nghệ khác
Tức là bạn sẽ self-host một phiên bản Deno khác với phiên bản mà phần lớn khách hàng Deno sử dụng
Có bao nhiêu người dùng Deno để chạy server trên phần cứng của chính mình? Nếu con số đó ít, tôi thà dùng Node hơn
Deno thật sự rất thú vị. Mô hình kinh doanh khả thi, trải nghiệm sử dụng tốt và không có những việc cấu hình lặt vặt vô ích là những điểm tuyệt vời
Bản thân Deno về cơ bản là Node.js cộng thêm khả năng tự động biên dịch TypeScript. Nếu làm theo cách thông thường thì chỉ cần thêm một tệp cấu hình nữa mà thôi. Khi dự án ra mắt, họ nhấn mạnh mạnh mẽ việc thoát khỏi hệ sinh thái NPM lộn xộn, nhưng cuối cùng lại phải quay lại bổ sung hỗ trợ NPM, và điểm khác biệt đó cũng biến mất
Deno Deploy giống như các dịch vụ kiểu Lambda vốn đã có hàng chục cái. Kho lưu trữ KV và giờ là hàng đợi thì tương đương với Redis, LevelDB, RocksDB, Dynamo, SQS hoặc vô số lựa chọn tương tự khác. Tôi vẫn chưa thấy tính năng nào thực sự phân biệt Deno với phần còn lại
Nếu bạn thích việc một công ty đảm nhiệm toàn bộ runtime ngôn ngữ, hosting tính toán và kho dữ liệu, thì nó có thể hấp dẫn. Nhưng cá nhân tôi muốn tránh điều đó, đặc biệt là khi công ty đó chưa có thành tích trong lĩnh vực ấy