Slide 1

Slide 1 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. T O R A N O A N A L a b 2024 Deno Queue を使って OGP画像の遅延作成をやってみる 2024/5/15 toranoana.deno #16 虎の穴ラボ株式会社 奥谷 一陽

Slide 2

Slide 2 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 自己紹介 奥谷 一陽 所属:虎の穴ラボ株式会社 興味:Deno、TypeScript 最近興味があるパッケージ:Effect X:@okutann88 github:Octo8080X

Slide 3

Slide 3 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 アジェンダ - Deno でOGP画像を作るには - Deno Deploy にOGP画像を保持するには - Deno Queue でOGP画像作成を遅延実行

Slide 4

Slide 4 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 こんなものを作っています


Slide 5

Slide 5 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 Echo-Echo Echo-Echo

Slide 6

Slide 6 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 Echo-Echo - Fresh + hono - ストレージにDeno KV を採用 - Deno Deploy で稼働 - 20秒までの短い音を投稿できるサイト Echo-Echo について詳しくはこちら https://speakerdeck.com/toranoana/freshto honodedeno-kvwoshi-idao-su

Slide 7

Slide 7 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 今回やりたいこと
 「Deno Deployにホストしたサイトで
 投稿に即したOGPを作りたい」


Slide 8

Slide 8 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 Deno でOGP画像を作るには


Slide 9

Slide 9 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 Deno で画像を扱えるモジュール - ImageScript:画像編集 - terminal_images:画像表示 - DenoChart:グラフ画像作成 - satori:JSX + CSS でSVGを作成できる - svg2png-wasm:SVGをpngに変換できる など 採用

Slide 10

Slide 10 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 Deno でOGP画像を作るには tsx + css - (satori) -> SVG - (svg2png-wasm) -> PNG で処理 import satori from "npm:satori"; import * as svg2png from "npm:svg2png-wasm"; await svg2png.initialize( await fetch("https://unpkg.com/svg2png-wasm/svg2png_wasm_bg.wasm"), ); export async function createOgp(id: string) { const svg = await satori(
***
, { width: 600, height: 315, }, ); const convert_options: svg2png.ConverterOptions = { defaultFontFamily: { sansSerifFamily: "Noto Sans JP", }, }; const png = await svg2png.svg2png(svg, convert_options); }

Slide 11

Slide 11 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 Deno でOGP画像を作るには tsx + css - (satori) -> SVG - (svg2png-wasm) -> PNG で処理 import satori from "npm:satori"; import * as svg2png from "npm:svg2png-wasm"; await svg2png.initialize( await fetch("https://unpkg.com/svg2png-wasm/svg2png_wasm_bg.wasm"), ); export async function createOgp(id: string) { const svg = await satori(
***
, { width: 600, height: 315, }, ); const convert_options: svg2png.ConverterOptions = { defaultFontFamily: { sansSerifFamily: "Noto Sans JP", }, }; const png = await svg2png.svg2png(svg, convert_options); }

Slide 12

Slide 12 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 Deno Deploy にOGP画像を保持するには


Slide 13

Slide 13 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 Deno Deploy にOGP画像を保持するには Deno Deployにホストしたアプリケーションで、 動的に作られた画像を保持する方法として、 - 外部のS3など - Deno KV などが選択肢になる 採用

Slide 14

Slide 14 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 Deno Deploy にOGP画像を保持するには 今回は、Deno KVの1レコードで画像を保持したい。 最初に1200 x 630 の画像を作ったが容量不足だった => 600 x 315 にサイズ変更にして対応

Slide 15

Slide 15 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 Deno Queue で
 OGP画像作成を遅延実行


Slide 16

Slide 16 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 Deno Queue でOGP画像作成を遅延実行 - Deno Queue は enqueue した内容を listenQueue で受け付ける   例 // app.ts const kv = await Deno.openKv(); kv.listenQueue((msg: unknown) => { console.log("listen message"); console.log(">> " + msg); }); await kv.enqueue("message 1", { delay: 1000 * 3 }); console.log("enqueue message"); > deno run --unstable-kv app.ts enqueue message listen message # << 3秒経過したら表示 >> message 1

Slide 17

Slide 17 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 Deno Queue でOGP画像作成を遅延実行 Deno Queue をFreshに導入した - listenQueue // utils/queues.ts import { createOgp } from "./create_ogp.tsx"; interface OgpMessage { type: "createOgp"; id: string; } function createOgpMessage(id: string) { return { type: "createOgp", id, }; } export async function callCreateOgp(id: string) { const kv = await Deno.openKv(); await kv.enqueue(createOgpMessage(id), { delay: 3000 }); } export async function listenQueue() { console.log("[START listenQueue]"); const kv = await Deno.openKv(); kv.listenQueue((msg: OgpMessage) => { if (msg.type === "createOgp") { createOgp(msg.id); } }); } // main.ts (抜粋) import "$std/dotenv/load.ts"; import { start } from "$fresh/server.ts"; import manifest from "./fresh.gen.ts"; import config from "./fresh.config.ts"; import { deleteData } from "./tasks/delete_task.ts"; import { listenQueue } from "./utils/queues.ts"; Deno.cron("Delete Task", "0 0 * * *", () => { deleteData(); }); listenQueue(); await start(manifest, config); main.ts でlistenQueueする処理の 呼び出しを行う

Slide 18

Slide 18 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 Deno Queue でOGP画像作成を遅延実行 Deno Queue をFreshに導入した - enqueue // utils/queues.ts import { createOgp } from "./create_ogp.tsx"; interface OgpMessage { type: "createOgp"; id: string; } function createOgpMessage(id: string) { return { type: "createOgp", id, }; } export async function callCreateOgp(id: string) { const kv = await Deno.openKv(); await kv.enqueue(createOgpMessage(id), { delay: 3000 }); } export async function listenQueue() { console.log("[START listenQueue]"); const kv = await Deno.openKv(); kv.listenQueue((msg: OgpMessage) => { if (msg.type === "createOgp") { createOgp(msg.id); } }); } // routes/api/[...path].ts(抜粋) import { callCreateOgp } from "../../utils/queues.ts"; const app = new OpenAPIHono(); const appRoutes = app // POST /api/recording .openapi(postRecordsRoute, async (c) => { const formData = await c.req.formData(); const blob = formData.get("file") as Blob; const title = formData.get("title") as string; const file = new Uint8Array(await blob.arrayBuffer()); const result = await saveRecord(title, file); await callCreateOgp(result.id); return c.json({ message: "OK", url: `/play/${result.id}` }); }) リクエストで enqueue する処理を呼び出し 今回の実装では、3秒後にOGP画像を作成開始

Slide 19

Slide 19 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 Deno Queue でOGP画像作成を遅延実行 Deno Queue をFreshに導入した // utils/queues.ts import { createOgp } from "./create_ogp.tsx"; interface OgpMessage { type: "createOgp"; id: string; } function createOgpMessage(id: string) { return { type: "createOgp", id, }; } export async function callCreateOgp(id: string) { const kv = await Deno.openKv(); await kv.enqueue(createOgpMessage(id), { delay: 3000 }); } export async function listenQueue() { console.log("[START listenQueue]"); const kv = await Deno.openKv(); kv.listenQueue((msg: OgpMessage) => { if (msg.type === "createOgp") { createOgp(msg.id); } }); } 今回遅延処理する内容は、OGP作成だけ。 しかし、他の処理もさせることを想定して、 処理内容を区別できるように実装。 キューイングできるのが、オブジェクトなのが 効いている!

Slide 20

Slide 20 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 まとめ


Slide 21

Slide 21 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 まとめ - Deno Deploy で画像が作成できる - Deno KVにデータをホストする場合、画像サイズに注意 - もし大きなものをホストしたい場合、kvdex や、kv-toolboxを検討する - さらに大きいなら、外部ストレージを検討する - Deno Queue は、オブジェクトでキューイングできるのはメリット - 重めな処理をどんどん、キューに入れてみよう

Slide 22

Slide 22 text

Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 2024 ありがとうございました