Deno キュー
(deno.com)- Deno Queues は Deno KV 上に構築されたサーバーレス分散キューで、時間のかかる処理を非同期に委譲したり、将来の時点での実行を予約したりできる
- 開発者は
.enqueue()でメッセージを投入し、.listenQueue()で処理すればよく、別途キュー用インフラを設定・維持する必要がない - ローカルでは SQLite、Deno Deploy では FoundationDB を使用し、Deploy はメッセージ処理のタイミングで V8 isolate をオンデマンドで起動して実行する
- 配信方式は at-least-once delivery であるため、障害や再試行時には同じメッセージが複数回処理される可能性がある
- キュー専用の追加課金はないが、enqueue は KV 書き込み、メッセージ受信は KV 書き込みと Deno Deploy リクエストとして計算されるため、重複処理とコスト構造をあわせて考慮する必要がある
Deno Queues が担う役割
- Deno Queues は Deno KV ベースのキュー機能で、アプリケーションの一部処理を非同期ジョブとして委譲したり、後で実行する処理を予約したりできる
- Deno はクラウドソフトウェア開発における繰り返しの設定やインフラ構成を減らし、開発者がより速く設計・改善・リリースできる基本要素を提供することを目指している
- Deno KV は FoundationDB ベースの永続化オプションで、現在はオープンベータの状態にある
- Queues は Deno KV 上で、スケーラブルなメッセージングとバックグラウンド処理管理を提供する
基本 API と実行方式
- Deno Queues の中核 API は 2 つある
.enqueue(): 新しいメッセージをキューに入れ、即時または将来の時点で配信されるようにする.listenQueue(): キューから新しいメッセージを受け取り処理するハンドラとして使う
- 基本的な流れは
Deno.openKv()で KV を開き、listenQueueで Slack メッセージを送信し、enqueueに{ delay: 60000 }を指定して 60 秒後に処理されるようにする方式である - 実行環境によってストレージが異なる
- ローカル実行時は SQLite を使用
- Deno Deploy 実行時は FoundationDB を使用
- Deno Deploy では、メッセージを処理可能な時点で V8 isolate をオンデマンドで実行し、メッセージをディスパッチする
- アプリケーションコードは
listenQueueハンドラで新しいメッセージを受け取ればよく、残りの実行管理は Deno Deploy が担う
配信保証と再試行
- Deno Queues は at-least-once delivery を保証する
- ほとんどの enqueue メッセージは
listenQueueハンドラを 1 回だけ呼び出すが、一部の失敗状況では配信保証のために同じハンドラが複数回呼び出されることがある - したがって、アプリケーションは重複メッセージ処理を安全に扱う必要がある
listenQueueハンドラが例外を投げると、ランタイムが呼び出しを自動的に再試行する- 再試行は成功するか最大再試行回数に達するまで続き、現在の既定最大値は5 回である
- 最大再試行回数に達したメッセージは削除される
KV atomic transaction と組み合わせて使う
- Deno Queues は KV atomic transactions と組み合わせて使える
- メッセージを KV トランザクションの一部として enqueue すると、トランザクション全体が成功した場合にのみメッセージがキューに入る
- 例の流れでは、Bob と Liz の残高を確認・更新したあと、2 人に通知メッセージを enqueue する
check(bob, liz)で状態を確認する- Bob の残高を減らし、Liz の残高を増やす
enqueueで Liz と Bob にそれぞれ通知メッセージを追加するcommit()が成功してはじめて、全変更と enqueue が反映される
listenQueueハンドラ内でも Deno KV の状態を更新できる- メッセージごとの更新を 1 回だけ実行するには、nonce を保存・削除する方式で重複処理防止のフローを構成できる
- enqueue 時に nonce もあわせて保存する
- 処理時に nonce がなければすぐに return する
- 処理成功時に nonce を削除し、カウンタと残高の状態をまとめて更新する
キューに適したユースケース
- キューはサーバーが非同期処理を委譲し、将来のジョブを予約できるようにするため、アプリケーションの拡張に有用である
-
予約メール通知
- ユーザーが開始した処理に時間がかかる、あるいは完了応答を待つ必要がない場合、キューに処理を委譲することでサーバーやアプリの応答性を維持できる
- 例では
welcome_emailメッセージを即時に enqueue し、survey_emailメッセージは{ delay: 259200000 }で遅延実行する
-
信頼性の高い Webhook 処理
- Webhook リクエストをすぐに処理せずキューに入れることで、応答と実際の処理を分離できる
- Oak と Queues を組み合わせて
/webhookへの POST リクエストを受け取ると、リクエスト本文をキューに入れて HTTP 200 を返す - 実際の Webhook 処理は
listenQueueでprocessWebHookとして非同期に実行する
-
Slack・Discord ボット
- Queues は Discord や Slack ボットの構築にも使える
- Slack reminder app 例 は、Deno Queues でシンプルな Slack リマインダーアプリを作る事例である
- Discord bot 例 は、Deno Queues で giveaway を作成し、ユーザーが 1 クリックで参加できるようにしている
- さらに多くのキュー活用例は docs.deno.com で確認できる
課金方式
- Deno Queues には専用の追加課金項目はない
- コストは Deno KV 操作と Deno Deploy リクエスト基準で計算される
- メッセージ enqueue: 各 enqueue 操作は KV 書き込み 1 件に相当する
- メッセージ受信: 受信メッセージごとに KV 書き込み 1 件とリクエスト課金 1 件が発生する
- 使用した操作分だけ課金される仕組みである
ドキュメントとロードマップ
- 関連ドキュメントと API リファレンス
- スケーラブルな Web アプリやサーバーを作るには、バックグラウンドジョブをキューに委譲する構成が必要だが、従来の方式はセットアップ手順が多い
- Deno Queues はランタイムに組み込まれ、Deno Deploy インフラ上で動作するため、数行のコードでサーバーレス分散キューを利用できる
- Deno Queues は Deno KV、web standards APIs、npm、all-in-one modern tooling と並び、Web 開発をシンプルかつ生産的にするための構成要素として位置付けられている
- フィードバックや機能要望は Discord または deploy_feedback issues から送ることができる
1件のコメント
Hacker Newsの意見
たった今、ローカルSQLite版の内部を掘り下げてメモをまとめました: https://til.simonwillison.net/deno/deno-kv#user-content-deno...
おそらく一番興味深いのは、この機能で使っているスキーマです:
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);インデックスはまさにそういう用途のために設計されているのでは?
かなり新しい一方で、少し不安でもあります。もちろん商用化は必要でしょうが、完全にクローズドな方式である必要はなかったはずで、拡張レイヤーにはBSLやPolyFormのような別のライセンスも使えたのではないかと思います
Denoがここで目指している方向性は、かなり未来志向だと思う
今年初めてGoを使っているが、言語の一部はCに非常によく似ている。Cと違う点、たとえばガベージコレクションのおかげで、関数からスタック割り当てポインタのように見える値を返せることに加えて、
map[string]stringのような組み込み機能が自然に入っている。2023年以降に新しい言語を作るなら、マップ型を扱う組み込み構文がないというのは、ほとんどあり得ないレベルだと感じただから、Webサーバー中心のエコシステムが、私たちがよく使うプリミティブ機能のためのライブラリ、ひょっとするといつかは言語構文まで備えるようになるのは論理的に見える。分散Webサーバーで、キャッシュ用のキー・バリューストア、ロック機構、一時キューすらなかった最後のプロジェクトを思い出せない。キー・バリューストアのない分散システムは、マップ型のないプログラミング言語にぼんやり似ていて、本当にスイスアーミーナイフのような技術だ
潜在的な問題は、Denoがこの道を単独で進んでいる点だ。現在Denoが追加している新機能が競合プラットフォームでも提供されるのか確信しにくいし、APIをオープンソースで公開したとしても
Deno名前空間にあるので、AWSでFoundationDBの代わりにRedisへ切り替えたいときにそのまま動くのかは分からないなので、Denoは避けたいという気持ちになる。構文や公開されている機能は本当に魅力的だが、依存した後で複数のクラウドインフラにデプロイできるようにするため、コードを大きく手術する必要が出るのではないかと心配になる。多くの顧客がそれを求めている。たとえば、いつかOracleやSalesforceに売り込みたいのにオンプレミス実行を要求されたら、そこで使えるキー・バリューストアを
Denoパッケージの機能に合わせてどう適用するかを自分が背負うことになる諸刃の剣だ。Denoがこのビジョンをより広い層に押し通すことに成功するかもしれないが、当面は慎重に見ることになりそうだ
このプロトコルを純粋なTypeScriptで実装した
kv-connect-kitを少し使ってみたが、どのJavaScriptランタイムでもKVクライアントAPIを提供する。Deno名前空間がまったくないCloudflare Workersも含まれるGitHub: 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 / デモ: https://keyspace.deno.dev/
プロトコルは説明どおりに動作するようで、別のバックエンドを書くのもかなり簡単そうだ
技術業界はベンダーロックインされたスタックから抜け出すためにかなり前進してきたのに、これはむしろそういう時代を思い出させる
Deno.KVがランタイムの一部として含まれることと、ファイルの先頭にimport KVを追加することの実質的な違いが何なのか分からない。後者ならDenoでもどこでも、好きな場所から取り込めるそしてDenoチームが自分たちの言語以外の言語向けバインディングを提供する可能性はどれくらいあるのだろうか? GoogleがGoにGoogle Cloud専用のプリミティブ機能をネイティブに入れ始めても、未来志向と呼ぶのだろうか?
同時に、自社ホスティングも業界トップと同等かそれ以上でなければならない。別の道としては、自社ホスティングをやめて、ホスティングパートナーのアダプターの上に薄いマージンを乗せたマルチクラウドソリューションを提供することもできる。そうすればDenoがホスティングプロバイダーとして直接競争する必要はなくなる
これは未来志向というより、DenoをSaaSとして収益化することに近いと思う。最近のJavaScript界隈で誰もが「クラウド」製品としてやっていること、つまりフレームワークを付けてAWSを再販売する流れだ。だから価格表が付いている
DenoのKVがFoundationDBに依存しているなら、他のデータベース向けアダプターを積極的に作る可能性も低そうだ。データベース技術を変えるのは常に大仕事で、それぞれ用途や性能特性が異なるからだ
GC allowing one to return what look like stack allocated pointers from functionsは、ガベージコレクションのおかげというよりエスケープ解析とSSAのおかげだと思う「パブリッククラウドのインフラを利用するには、ボイラープレートコードや複雑な設定を掘り返さなければならず、開発者の時間とエネルギーを大きく消耗する」という論理にはあまり納得できない
結局のところ、私たちは安定しているべきインフラを作っている。実績ある技術である SQS キューを設定するのに30分使うことが、Deno が「SQLite / FoundationDB の上に」作ったおもちゃのキューを全面的に信頼することより悪いようには見えない。30分の設定コストと改善された「開発者体験」は、本当にそのリスクを取るほどの価値があるのか? そもそもキューをどれくらい頻繁に設定するのか?
趣味のプログラマーとしては、AWS や Google のような大手プロバイダーはあまり使わない。かなり複雑に見えるからだ。慣れていればそこまで悪くないのかもしれない
それに各プロジェクトは GitHub の独立したリポジトリとして置いておきたい。理想的には、Web アプリを誰でも別ドメインで、自分の独立した Web アプリのように簡単に立ち上げられるべきだ。他人のデータまで責任を負いたくないからだ
これはある程度 Sandstorm のユースケースに似ている。「ローカルで試してみて、実際に使うなら Deno Deploy アカウントを作れ」というインストール案内は、かなり妥当に聞こえる
クラウド向けに同等のライブラリを誰かが提供すれば、間違いなく採用する人たちはいるはずだ。Deno の場合、自分たちのエコシステムの開発者が抱える共通の問題を見つけ、妥当な解法をまとめて解決しようとしているように見える
キューを抽象化してくれる ワークフローエンジンを使えば、タスク、スケジュール、状態、リトライを管理せずに「ただコードを書く」ことができる
https://www.inngest.com/blog/how-durable-workflow-engines-wo...
ただし、私はワークフローエンジンの作者なので偏りはある
「少なくとも1回の配信セマンティクス」と「ユーザーコード」を扱った以前の経験からすると、ユーザーは 少なくとも1回の配信を正しく理解していない
メッセージを再配信した瞬間、ユーザーの不満と障害が押し寄せる
不可能に近いことをやり遂げて正確に1回の配信セマンティクスを発明するか、そうでなければユーザーが1回だけ配信されると依存できないよう、すべてのメッセージの0.1%を常に再配信すべきだと思う
現在 Deno Deploy を使っているが、個人で作るプロジェクトという基準では性能が素晴らしく、本当にシンプルだ
大きなチームで AWS 開発をした立場からすると、設定を考えなくても簡単に立ち上げられるように複雑さから離れていく流れはうれしい。DNS も非常に簡単で、自動 SSL 証明書も本当に良かった。この製品が目指している方向にはまったく不満がなく、ロードマップにも期待している
私が見落としていなければ、
Deno.openKv()インスタンスごとに キューが1つしかないように見えるローカル版では、毎回別の SQLite ファイルパスで
Deno.openKv("db-2.db")を呼べば複数のキューを作れるだろうが、かなり一般的な要件に対してオーバーヘッドが大きく見えるおそらく Deno のアーキテクチャスタイルなのかもしれない。複雑なアプリを Deno で作るときは、複数のスクリプトが一緒に動作し、それぞれが自分の KV ストアとキューを持つマイクロサービス的な構造を期待しているのだろうか?
コア開発者の1人が Discord で確認してくれた: https://discord.com/channels/684898665143206084/115671428253...
引用すると: 「その通りです。現在は単一キューのみをサポートしています。ただし単一キュー内で複数タイプのメッセージを多重化することはできます。」
価格はどうなっているのか?
Deno は一種の Node.js 代替だと思っていたのだが、何か見落としているのだろうか? これはローカルやセルフホスティングで無料で使えるのか?
「Queues are built on Deno KV」なので、ローカルでは SQLite を使い、Deno Deploy では最大限の可用性とスループットのために FoundationDB を使う、という説明だ
このパターンについてはここにもう少し書いてある: https://til.simonwillison.net/deno/deno-kv
もし開発者が見ているなら、現在の優れた KV の使い勝手において アクセス制御のあたりは、後で苦痛が生じそうに思う
解決策が単に「ユーザー空間で自分で実装して、バグを作らないようにする」なのか、それとも何か計画があるのか気になる
最近の Jupyter サポートと今回のキュー機能には期待している。本当に素晴らしいものだ
ただ、Deno でサーバーを書いて自分のサーバーで本番運用することはなさそうだ。サーバーレスは好きではない
Deno と Bun のビジネスモデルはサーバーレス、つまり Deno Deploy を中心に作られている。そして Deno Deploy はまた別のランタイムだ
KV とキューではその点が明らかだ。ローカルやセルフホスティングでは、別の技術の上に載った、かろうじて動くバージョンを持つことになる
つまり、Deno の顧客の大多数が使っているものとは別バージョンの Deno をセルフホスティングすることになる
自分のハードウェアでサーバーを動かすために Deno を使う人はどれくらいいるのだろうか? その数が少ないなら、むしろ Node を使う
Deno は本当に興味深い。実現可能なビジネスモデル、優れた使い勝手、無駄な設定作業がない点が素晴らしい
Deno 自体は本質的に、Node.js に TypeScript の自動コンパイルを加えたものだ。本来なら設定ファイルが1つ余分に必要だっただけだ。プロジェクトが登場したときは、雑然とした NPM エコシステムから脱却できる点を大きく打ち出していたが、結局は方針を変えて NPM サポートを追加せざるを得ず、その差別化要素も消えてしまった
Deno Deploy は、すでに何十も存在する Lambda 系サービスと同じだ。KV ストアと、今回のキューは、Redis、LevelDB、RocksDB、Dynamo、SQS、または数多くの類似オプションと同等だ。Deno を他と実際に区別してくれる機能は、まだ一つも見ていない
言語ランタイム、コンピュートホスティング、データストアを1社がすべて担うことを好むなら、魅力があるかもしれない。だが個人的には避けたいし、特にその会社にその分野での実績がないならなおさらだ