Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Go言語で始めるCloudflare Workers
Search
syumai
December 15, 2023
Programming
4.3k
9
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Go言語で始めるCloudflare Workers
https://github.com/syumai/workers
の紹介です。
syumai
December 15, 2023
More Decks by syumai
See All by syumai
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.5k
Oxlintのカスタムルールの現況
syumai
6
1k
Oxlintはいかにしてtsgolintのlint ruleを呼び出しているのか
syumai
2
1.1k
『[入門] Cloudflare Workers』本はなぜ誕生したのか
syumai
0
360
tsgolintはいかにしてtypescript-goの非公開APIを呼び出しているのか
syumai
9
3.1k
知られているようで知られていない JavaScriptの仕様 4選
syumai
3
1.2k
CloudflareのSandbox SDKを試してみた
syumai
0
840
実践AIチャットボットUI実装入門
syumai
9
4.2k
ProxyによるWindow間RPC機構の構築
syumai
3
1.5k
Other Decks in Programming
See All in Programming
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
170
コンテキストの使い捨てをやめる — ビジネスルール駆動開発と miko —
ioki
0
140
ふつうのFeature Flag実践入門
irof
7
3.6k
AIで効率化できた業務・日常
ochtum
0
100
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
0
160
New "Type" system on PicoRuby
pocke
1
480
DynamoDBには集計系のクエリがないけどなんとかしたい
musan
1
130
PHPで使える日時の表現と、その知り方 #frontend_phpcon_do
o0h
PRO
0
190
Spec-Driven Development with AI-Agents: From High-Level Requirements to Working Software
antonarhipov
2
470
Copilot CLI の継戦能力を高める コンテキスト管理
nozomutu
1
1.2k
These Five Tricks Can Make Your Apps Greener, Cheaper, & Nicer
hollycummins
0
270
フロントエンドとバックエンドで「1文字」を揃えよう
youkidearitai
PRO
0
220
Featured
See All Featured
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.9k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
720
The Art of Programming - Codeland 2020
erikaheidi
57
14k
Building Adaptive Systems
keathley
44
3k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
55k
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
2
840
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
300
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.3k
Making Projects Easy
brettharned
120
6.7k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
65
55k
Practical Orchestrator
shlominoach
191
11k
Crafting Experiences
bethany
1
170
Transcript
Go で始めるCloudflare Workers syumai Workers Tech Talks #2 (2023/12/15)
自己紹介 syumai ECMAScript 仕様輪読会 主催 株式会社ベースマキナで管理画面のSaaS を開発中 Go でGraphQL サーバー
(gqlgen) や TypeScript でフロント エンドを書いています Software Design 12 月号からCloudflare Workers の連載をして ます Twitter: @__syumai Website: https://syum.ai
None
ベースマキナとは? DB やAPI の接続設定 & 呼び出し設定をするだけで、簡単にUI 生成が行える管理画面 SaaS API 呼び出しへの権限設定や、レビュー依頼
/ 承認機能も簡単に使えます https://about.basemachina.com
本日話すこと syumai/workers の紹介 デモ syumai/workers の仕組み どんなアプリケーションが動くか パフォーマンス 注意点 今後の展望
syumai/workers の紹介
workers https://github.com/syumai/workers http.Handler を作って、 workers.Serve に渡すだけでCloudflare Workers 上でHTTP サ ーバーとして動作する
http.ListenAndServe の代わりに workers.Serve 関数を呼ぶ形にするだけ TinyGo / Go を使ってWebAssembly を生成して実行する JavaScript 側のコードを触る必要が無い Cloudflare の機能のバインディングを提供 (R2, KV, D1 など)
作ったモチベーション WebAssembly とJavaScript の知識が無くてもGo でWorker を書けるようにしたかった 最終的に、gonew コマンドでtemplate からプロジェクト生成するだけで済む形に なった
実用的なWorker をGo で短時間で実装できるようなライブラリが欲しかった
デモ
デモ syumai/workers のQuick Start を実行してみます
Quick Start 必要なツール Node.js ( とnpm) wrangler npm install -g
wrangler . tinygo 0.29.0 以上 gonew go install golang.org/x/tools/cmd/gonew@latest 最近Go 公式から試験的なものとして出た、Go のプロジェクトをテンプレートから 立ち上げるためのコマンド
プロジェクトの作成 $ gonew github.com/syumai/workers/_templates/cloudflare/worker-tinygo your.module/my-app $ cd my-app $ go
mod tidy $ make dev # 開発サーバーの起動 $ curl http://localhost:8787/hello # outputs "Hello!" 今回は、 モジュール名を github.com/syumai/workers-tech-talk/hello-tinygo に します
ファイル構成 ├── Makefile ├── README.md ├── build # ここはいじる必要がない │
├── app.wasm │ ├── polyfill_performance.js │ ├── shim.mjs │ ├── wasm_exec.js │ └── worker.mjs ├── go.mod ├── go.sum ├── main.go # アプリケーション本体 └── wrangler.toml
アプリケーションの中身 func main() { http.HandleFunc("/hello", func(w http.ResponseWriter, req *http.Request) {
msg := "Hello!" w.Write([]byte(msg)) }) http.HandleFunc("/echo", func(w http.ResponseWriter, req *http.Request) { io.Copy(w, req.Body) }) workers.Serve(nil) // use http.DefaultServeMux } 普通のHTTP Server 同様、HandleFunc を使っているだけ /hello ハンドラーの実装を変更すると、curl の結果が変わるのが確認できる
デプロイ make deploy で完了 アプリ名を変えたい場合は、 wrangler.toml を編集する
syumai/workers の仕組み
syumai/workers の仕組み Cloudflare Workers は、基本的にRequest オブジェクトを処理し、Response オブジェクトを 返すと言う構造になっているため、下記が実装できればOK JavaScript 側で受け取ったRequest
オブジェクトをGo に渡す Go 側でResponse オブジェクトを組み立ててJavaScript 側に渡す これをGo の標準ライブラリのsyscall/js を使って実装した
syumai/workers の仕組み Worker のendpoint は(当然ながら)JS JS 側は、Go 側の初期化処理が終わるのを待つためのPromise を作成してglobalThis に設
定する Go 側の初期化処理で、Go にJS のRequest オブジェクトを渡すための handleRequest 関数をglobalThis に設定する Go 側の初期化処理が終わったら、Promise を解決 JS 側からhandleRequest 関数を呼んで、結果を返す
Worker のendpoint (JS 側) のコード async function run() { //
Go側の初期化完了を待つPromiseをglobalThisに設定 const readyPromise = new Promise((resolve) => { globalThis.ready = resolve; }); const instance = new WebAssembly.Instance(mod, go.importObject); go.run(instance); await readyPromise; } // Fetch Handlerを使うのは普通のWorkerと同じ export async function fetch(req, env, ctx) { await run(); // RequestをJS側からGo側に渡して処理する return handleRequest(req, { env, ctx }); } https://github.com/syumai/workers/blob/v0.18.0/cmd/workers-assets- gen/assets/common/shim.mjs
Go 側の初期化処理のコード ( 色々省略しています) init 関数の中で、JS 側からGo 側にRequest オブジェクトを渡して処理する handleRequest
関数をglobalThis に設定する func init() { handleRequestCallback := js.FuncOf(func(this js.Value, args []js.Value) any { reqObj := args[0] cb := js.FuncOf(func(_ js.Value, pArgs []js.Value) any { resolve := pArgs[0] go func() { res := handleRequest(reqObj) resolve.Invoke(res) }() return js.Undefined() }) return jsutil.NewPromise(cb) }) jsutil.Global.Set("handleRequest", handleRequestCallback) } https://github.com/syumai/workers/blob/v0.18.0/handler.go
Go 側の初期化処理のコード workers.Serve 関数が呼ばれた時点では既にmain 関数の処理に入っており、init 関数 の処理は終わっているので、JS 側で待ち受けていたPromise を解決する func
Serve(handler http.Handler) { if handler == nil { handler = http.DefaultServeMux } httpHandler = handler jsutil.Global.Call("ready") select {} } https://github.com/syumai/workers/blob/v0.18.0/handler.go
変換処理 Go 側、JS 側でストリームの変換処理が必要 Go のhttp.ResponseWriter -> JS のReadableStream この辺りの話はZenn
に書きました Cloudflare Workers で簡単にGo のHTTP サーバーを動かすためのライブラリを作っ た - https://zenn.dev/syumai/articles/ca9n4e91eqljc44k6ebg
どんなアプリケーションが動くか
gqlgen 製のGraphQL サーバー
gqlgen 製のGraphQL サーバー gqlgen 公式から拾ってきたSTAR WARS server STAR WARS 関連の情報をGraphQL
経由で引っ張るAPI 通常のGo を使っています (2023 年12 月現在、TinyGo では動作しませんでした) https://gqlgen-starwars-example.syumai.workers.dev/ https://github.com/syumai/workers-playground/tree/main/gqlgen-starwars-example こんな感じのクエリを投げると結果が返ってくる query Starships { starship(id: "3003") { id name length history } }
connect-go 製のサーバー 事前に定義したProtobuf をベースに、Buf でconnect-go のコードを生成、サーバーを実 装したもの 通常のGo を使っています (2023
年12 月現在、TinyGo では動作しませんでした) https://emoji.syum.ai message GetEmojiRequest { string short_name = 1; } message Emoji { string short_name = 1; string emoji = 2; } service EmojiService { rpc GetEmoji(GetEmojiRequest) returns (GetEmojiResponse) {} }
connect-go 製のサーバー $ curl -s -H 'Content-Type: application/json' \ https://emoji.syum.ai/emoji.v1.EmojiService/GetEmoji
\ -d '{"short_name": "star"}' | gzip -d | jq . { "emoji": { "shortName": "star", "emoji": " " } } 実装はこちら: https://github.com/syumai/workers-playground/blob/main/connect-go- emoji-server
画像生成サーバー Go 製のsyumai のプロフィールページ TinyGo で動いています もともとGoogle App Engine で動いていたもの
を、Cloudflare Workers に移管した グリーンピースの色をランダムに変化させて表 示したりする https://syum.ai/
画像生成サーバー image/png の利用イメージ import "image/png" func writePNG(w http.ResponseWriter, cMap syumaigen.ColorMap)
{ w.Header().Set("Content-Type", "image/png") img, _ := syumaigen.GenerateImage( syumaigen.Pattern, cMap, 10, ) var buf bytes.Buffer png.Encode(&buf, img) w.WriteHeader(http.StatusOK) io.Copy(w, &buf) } https://github.com/syumai/syum.ai/blob/main/server/image.go
その他 D1 を使ったブログサーバー https://github.com/syumai/workers/tree/main/_examples/d1-blog-server Pages Functions をGo のAPI にする例 https://github.com/syumai/workers/tree/main/_examples/pages-functions
/functions/api/[[routes]].mjs を丸ごとGo にルーティングする形式
活用イメージ Go 製のちょっとしたアプリをデプロイする先として リクエストのあった時しか起動しないので、インスタンスを常時起動するタイプ のサービスを使うより安上がり D1 やKV も使える Scheduled Handler
(Cron Trigger) も使える ( あんまり無いかも) Cloudflare Pages のBackend API として Pages Functions で、普通にGo のAPI サーバーが動かせる
パフォーマンス
パフォーマンス syum.ai (TinyGo 製) を対象に、hey でベンチマークを行った結果を示します 実行タイミングによって、結果にバラつきがある点ご了承ください
静的HTML 配信のベンチマーク (hey https://syum.ai で200req) Summary: Total: 0.2159 secs Slowest:
0.1564 secs Fastest: 0.0164 secs Average: 0.0427 secs Requests/sec: 926.2291 Response time histogram: 0.016 [1] | 0.030 [144] |▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪ 0.044 [5] |▪ 0.058 [5] |▪ 0.072 [2] |▪ 0.086 [0] | 0.100 [0] | 0.114 [26] |▪▪▪▪▪▪▪ 0.128 [10] |▪▪▪ 0.142 [6] |▪▪ 0.156 [1] | Latency distribution: 10% in 0.0182 secs 25% in 0.0197 secs 50% in 0.0216 secs 75% in 0.0508 secs 90% in 0.1131 secs 95% in 0.1256 secs 99% in 0.1304 secs <- 99 percentileで約130ms
画像生成のベンチマーク (hey https://syum.ai/image で200req) Summary: Total: 0.3666 secs Slowest: 0.1868
secs Fastest: 0.0253 secs Average: 0.0608 secs Requests/sec: 545.4886 Response time histogram: 0.025 [1] | 0.041 [127] |▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪ 0.058 [20] |▪▪▪▪▪▪ 0.074 [0] | 0.090 [1] | 0.106 [0] | 0.122 [18] |▪▪▪▪▪▪ 0.138 [23] |▪▪▪▪▪▪▪ 0.154 [1] | 0.171 [7] |▪▪ 0.187 [2] |▪ Latency distribution: 10% in 0.0296 secs 25% in 0.0341 secs 50% in 0.0384 secs 75% in 0.1172 secs 90% in 0.1294 secs 95% in 0.1390 secs 99% in 0.1773 secs <- 99 percentileで約180ms
注意点
Worker のファイルサイズ制限 無料プランだと、圧縮後のサイズが1MB 以内でないといけない制約があるため、バイ ナリサイズが大きくなる通常のGo ではpublish 出来ない TinyGo じゃないと基本的に無理 有料プランなら、10MB
までアップロード可能なので、通常のGo でもある程度のアプ リケーションが動かせる
TinyGo の制限 最近は問題がなくなりつつある 2023 年、ついにencoding/json も動くようになった ただし、複雑なアプリケーションでは、時々ビルドが通らないケースがある ビルドにやや時間がかかる 欠点を補って余りある優位性 (
バイナリサイズの小ささ) があるので、個人的には積極 的に使いたい
今後の展望
TCP sockets 対応 Cloudflare Workers 的には、 cloudflare:sockets の connect 関数でTCP
sockets に 対応している これを使えばTCP 上で動作する任意のプロトコルが使えるようになるので、あらゆる DB が選択肢に入る Go 製のDB ドライバが使えるのは魅力的 コネクションプールの問題も、Hyperdrive が登場したことにより、ある程度解消が見 込めるのでセットで使いたい 実はPR はもらっている 年末年始休暇で何とかします!
ご清聴ありがとうございました!