1 ポイント 投稿者 GN⁺ 2023-09-29 | 1件のコメント | WhatsAppで共有
  • 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 処理は listenQueueprocessWebHook として非同期に実行する
  • 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 APIsnpmall-in-one modern tooling と並び、Web 開発をシンプルかつ生産的にするための構成要素として位置付けられている
  • フィードバックや機能要望は Discord または deploy_feedback issues から送ることができる

1件のコメント

 
GN⁺ 2023-09-29
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);

    • ほぼ同じフィールドを持つ2つのテーブルを作って行を移すのは、普通は悪いプラクティスではないかと思います
      インデックスはまさにそういう用途のために設計されているのでは?
    • 「オープンソースのビジネスモデル」という観点で特に興味深いのは、Denoがフレームワークの中核機能に、自社のSaaSプラットフォームだけがグローバル規模のアップグレードとしてうまく提供できる機能を入れている点です
      かなり新しい一方で、少し不安でもあります。もちろん商用化は必要でしょうが、完全にクローズドな方式である必要はなかったはずで、拡張レイヤーにはBSLPolyFormのような別のライセンスも使えたのではないかと思います
  • Denoがここで目指している方向性は、かなり未来志向だと思う
    今年初めてGoを使っているが、言語の一部はCに非常によく似ている。Cと違う点、たとえばガベージコレクションのおかげで、関数からスタック割り当てポインタのように見える値を返せることに加えて、map[string]stringのような組み込み機能が自然に入っている。2023年以降に新しい言語を作るなら、マップ型を扱う組み込み構文がないというのは、ほとんどあり得ないレベルだと感じた
    だから、Webサーバー中心のエコシステムが、私たちがよく使うプリミティブ機能のためのライブラリ、ひょっとするといつかは言語構文まで備えるようになるのは論理的に見える。分散Webサーバーで、キャッシュ用のキー・バリューストア、ロック機構、一時キューすらなかった最後のプロジェクトを思い出せない。キー・バリューストアのない分散システムは、マップ型のないプログラミング言語にぼんやり似ていて、本当にスイスアーミーナイフのような技術だ
    潜在的な問題は、Denoがこの道を単独で進んでいる点だ。現在Denoが追加している新機能が競合プラットフォームでも提供されるのか確信しにくいし、APIをオープンソースで公開したとしてもDeno名前空間にあるので、AWSでFoundationDBの代わりにRedisへ切り替えたいときにそのまま動くのかは分からない
    なので、Denoは避けたいという気持ちになる。構文や公開されている機能は本当に魅力的だが、依存した後で複数のクラウドインフラにデプロイできるようにするため、コードを大きく手術する必要が出るのではないかと心配になる。多くの顧客がそれを求めている。たとえば、いつかOracleやSalesforceに売り込みたいのにオンプレミス実行を要求されたら、そこで使えるキー・バリューストアをDenoパッケージの機能に合わせてどう適用するかを自分が背負うことになる
    諸刃の剣だ。Denoがこのビジョンをより広い層に押し通すことに成功するかもしれないが、当面は慎重に見ることになりそうだ

    • この場合は、リモート接続プロトコルであるKV Connectも文書化されている: https://github.com/denoland/deno/tree/main/ext/kv#kv-connect
      このプロトコルを純粋な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/
      プロトコルは説明どおりに動作するようで、別のバックエンドを書くのもかなり簡単そうだ
    • 同意しない。言語ランタイムを、特定のホスティングサービスに結び付いた特定のKVインターフェースと結合するのは、未来志向の反対だ
      技術業界はベンダーロックインされたスタックから抜け出すためにかなり前進してきたのに、これはむしろそういう時代を思い出させる
      Deno.KVがランタイムの一部として含まれることと、ファイルの先頭にimport KVを追加することの実質的な違いが何なのか分からない。後者ならDenoでもどこでも、好きな場所から取り込める
      そしてDenoチームが自分たちの言語以外の言語向けバインディングを提供する可能性はどれくらいあるのだろうか? GoogleがGoにGoogle Cloud専用のプリミティブ機能をネイティブに入れ始めても、未来志向と呼ぶのだろうか?
    • Denoは好きだが、同じ理由で導入には慎重になる。Denoが勝つには、ホスティングの競合も完全にサポートする必要があると思う
      同時に、自社ホスティングも業界トップと同等かそれ以上でなければならない。別の道としては、自社ホスティングをやめて、ホスティングパートナーのアダプターの上に薄いマージンを乗せたマルチクラウドソリューションを提供することもできる。そうすればDenoがホスティングプロバイダーとして直接競争する必要はなくなる
    • Denoはこれで他のJS/TS SaaSと競争しようとしているだけだ。Vercel/NextJSにもKVサービスがあり、Cloudflareにもあり、他の場合にはFirebaseがある
      これは未来志向というより、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 アカウントを作れ」というインストール案内は、かなり妥当に聞こえる
    • 多くの人は AWS や SQS の経験がなく、経験がある人でもなお気を使う必要がある。Deno は バッテリー同梱のアプローチを選び、開発者が何かを手に取ってすぐ使えるようにしている
      クラウド向けに同等のライブラリを誰かが提供すれば、間違いなく採用する人たちはいるはずだ。Deno の場合、自分たちのエコシステムの開発者が抱える共通の問題を見つけ、妥当な解法をまとめて解決しようとしているように見える
    • 極端に言えば、今ではキューを直接使わないほうがいいと思う。生の HTTP/2 を使ったり、スレッドを直接管理したりするのに似ている
      キューを抽象化してくれる ワークフローエンジンを使えば、タスク、スケジュール、状態、リトライを管理せずに「ただコードを書く」ことができる
      https://www.inngest.com/blog/how-durable-workflow-engines-wo...
      ただし、私はワークフローエンジンの作者なので偏りはある
    • その理屈だと、新しく出てくるものは基本的に「おもちゃプロジェクト」で、AWS だけが検証済みなのだから、誰も新製品を出してはいけないということになる
    • それがおもちゃのキューだとどうして分かるのか?
  • 「少なくとも1回の配信セマンティクス」と「ユーザーコード」を扱った以前の経験からすると、ユーザーは 少なくとも1回の配信を正しく理解していない
    メッセージを再配信した瞬間、ユーザーの不満と障害が押し寄せる
    不可能に近いことをやり遂げて正確に1回の配信セマンティクスを発明するか、そうでなければユーザーが1回だけ配信されると依存できないよう、すべてのメッセージの0.1%を常に再配信すべきだと思う

    • 初期の SQS は実質的にこうだった。意図的だったのかは分からないが、そのおかげで再配信を尊重しなければならないことをすぐに学べた
    • メッセージが 冪等でなければならないなら、送信側でそれを保証する統合テストを必ず作ることを勧める
  • 現在 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 代替だと思っていたのだが、何か見落としているのだろうか? これはローカルやセルフホスティングで無料で使えるのか?

    • これは Deno KV の他の部分と同じ仕組みだ。オープンソース版は SQLite を使うが、Deno のクラウド製品にデプロイすると、代わりにプロプライエタリな FoundationDB を使うことになる
      「Queues are built on Deno KV」なので、ローカルでは SQLite を使い、Deno Deploy では最大限の可用性とスループットのために FoundationDB を使う、という説明だ
      このパターンについてはここにもう少し書いてある: https://til.simonwillison.net/deno/deno-kv
    • 記事によると、開発中のローカルでは SQLite を使い、Deno にデプロイするとクラウド提供機能の一部になる
  • もし開発者が見ているなら、現在の優れた KV の使い勝手において アクセス制御のあたりは、後で苦痛が生じそうに思う
    解決策が単に「ユーザー空間で自分で実装して、バグを作らないようにする」なのか、それとも何か計画があるのか気になる

    • ユーザーレベルのアクセス制御、例えば認証済みユーザー向けの ACL のようなものを言っているのか、それとも別のことなのか気になる。もう少し詳しい考えを共有してくれれば、この懸念を引き続き念頭に置いておく
  • 最近の Jupyter サポートと今回のキュー機能には期待している。本当に素晴らしいものだ
    ただ、Deno でサーバーを書いて自分のサーバーで本番運用することはなさそうだ。サーバーレスは好きではない
    Deno と Bun のビジネスモデルはサーバーレス、つまり Deno Deploy を中心に作られている。そして Deno Deploy はまた別のランタイムだ
    KV とキューではその点が明らかだ。ローカルやセルフホスティングでは、別の技術の上に載った、かろうじて動くバージョンを持つことになる
    つまり、Deno の顧客の大多数が使っているものとは別バージョンの Deno をセルフホスティングすることになる
    自分のハードウェアでサーバーを動かすために Deno を使う人はどれくらいいるのだろうか? その数が少ないなら、むしろ Node を使う

  • Deno は本当に興味深い。実現可能なビジネスモデル、優れた使い勝手、無駄な設定作業がない点が素晴らしい

    • Deno に期待してみようとは思ったが、よく分からない。過去に何度も行われてきたことと何が違うのか見えない
      Deno 自体は本質的に、Node.js に TypeScript の自動コンパイルを加えたものだ。本来なら設定ファイルが1つ余分に必要だっただけだ。プロジェクトが登場したときは、雑然とした NPM エコシステムから脱却できる点を大きく打ち出していたが、結局は方針を変えて NPM サポートを追加せざるを得ず、その差別化要素も消えてしまった
      Deno Deploy は、すでに何十も存在する Lambda 系サービスと同じだ。KV ストアと、今回のキューは、Redis、LevelDB、RocksDB、Dynamo、SQS、または数多くの類似オプションと同等だ。Deno を他と実際に区別してくれる機能は、まだ一つも見ていない
      言語ランタイム、コンピュートホスティング、データストアを1社がすべて担うことを好むなら、魅力があるかもしれない。だが個人的には避けたいし、特にその会社にその分野での実績がないならなおさらだ
    • Deno に実現可能なビジネスモデルがあると信じる理由は何か?