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.4k
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.6k
Oxlintのカスタムルールの現況
syumai
6
1.1k
Oxlintはいかにしてtsgolintのlint ruleを呼び出しているのか
syumai
2
1.2k
『[入門] Cloudflare Workers』本はなぜ誕生したのか
syumai
0
380
tsgolintはいかにしてtypescript-goの非公開APIを呼び出しているのか
syumai
9
3.1k
知られているようで知られていない JavaScriptの仕様 4選
syumai
3
1.2k
CloudflareのSandbox SDKを試してみた
syumai
0
860
実践AIチャットボットUI実装入門
syumai
9
4.2k
ProxyによるWindow間RPC機構の構築
syumai
3
1.5k
Other Decks in Programming
See All in Programming
セキュリティの専門家じゃなくてもできる。「セキュリティ意識」をアップデートして サプライチェーン攻撃への耐性を高めよう。
tk3fftk
5
750
並列実装の現場、2ヶ月間実務でAIを使い倒したAIもPCも私も限界が近い
ming_ayami
0
130
AI時代のUIはどこへ行く?その2!
yusukebe
21
7.1k
Signal Forms: Beyond the Basics @ngBaguette 2026 in Paris
manfredsteyer
PRO
0
250
Agentic UI
manfredsteyer
PRO
0
160
代数的データ型って何が嬉しいの? #frontend_phpcon_do
kajitack
8
3.7k
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
130
タクシーアプリ『GO』の バックエンド開発のおける AI利活用と若者のすべて
pyama86
3
2k
The ROI of Quarkus for Spring Boot Applications
hollycummins
0
120
[2026年度第1回ORセミナー] 計画最適化ベンチャーと競技プログラミング人材
terryu16
0
260
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
760
AIで効率化できた業務・日常
ochtum
0
130
Featured
See All Featured
Utilizing Notion as your number one productivity tool
mfonobong
4
320
Skip the Path - Find Your Career Trail
mkilby
1
150
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
580
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
430
WENDY [Excerpt]
tessaabrams
11
38k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
The Curious Case for Waylosing
cassininazir
1
390
Git: the NoSQL Database
bkeepers
PRO
432
67k
A Modern Web Designer's Workflow
chriscoyier
698
190k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
52k
Large-scale JavaScript Application Architecture
addyosmani
515
110k
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 はもらっている 年末年始休暇で何とかします!
ご清聴ありがとうございました!