Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Cloudflare WorkersでGoのHTTPサーバーを動かすライブラリを作った話
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
syumai
August 01, 2022
Programming
980
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Cloudflare WorkersでGoのHTTPサーバーを動かすライブラリを作った話
Zennに投稿した下記の記事に基づく発表です。
https://zenn.dev/syumai/articles/ca9n4e91eqljc44k6ebg
syumai
August 01, 2022
More Decks by syumai
See All by syumai
自分的「カンファレンスの楽しみ方」
syumai
0
200
go-spidermonkeyでAIエージェントのCode Modeを実装する
syumai
3
1.5k
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.9k
Oxlintのカスタムルールの現況
syumai
6
2k
Oxlintはいかにしてtsgolintのlint ruleを呼び出しているのか
syumai
2
1.5k
『[入門] Cloudflare Workers』本はなぜ誕生したのか
syumai
0
590
tsgolintはいかにしてtypescript-goの非公開APIを呼び出しているのか
syumai
9
3.3k
知られているようで知られていない JavaScriptの仕様 4選
syumai
3
1.3k
CloudflareのSandbox SDKを試してみた
syumai
0
1k
Other Decks in Programming
See All in Programming
新卒PdEのリアル
ryu1013
1
480
AI × TiDD / 2026.09.05 Redmine 大阪
tokudiro
1
120
AWS Step Functions 大規模並列の壁を越える / jaws-sonic-2026-niigata-step-functions
kasacchiful
PRO
1
430
Snowflakeで業務アプリを作ろう。 Snowflakeのアプリ機能解説&実践ガイド
ayumu_yamaguchi
1
210
DroidKaigi 2026 「個人開発という実験場: Android エンジニアが手にする4つの自由」
slashnephy
0
230
LLMは4年分のCompose移行を再現できるのか?実プロダクト279件のXMLで探る自動化の境界線
makun
0
500
Swift愛好会と私(ウホーイ) / Swift Fan Club and Uhooi
uhooi
0
150
【DroidKaigi 2026】「アクセシビリティを利用するとき、 アクセシビリティもまたこちらを利用している」 〜マルウェアによる攻撃と防衛について〜
halunoyo
0
440
Swift愛好会100回記念 第1回を振り返る
jollyjoester
0
120
信頼性の目標を誰も求めてない
shubox
0
500
Hello, Hiroshima Geospatial Data! — Exploring DoboX with Python
ra0kley
0
180
マイコン向けの軽量Ruby「PicoRuby」で各種デバイスを制御するネイティブアプリの実現手法
bash0c7
0
320
Featured
See All Featured
YesSQL, Process and Tooling at Scale
rocio
174
15k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2.2k
Ethics towards AI in product and experience design
skipperchong
2
370
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
240
Java REST API Framework Comparison - PWX 2021
mraible
34
9.7k
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
320
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.8k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
730
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
270
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
490
WCS-LA-2024
lcolladotor
0
820
It's Worth the Effort
3n
188
29k
Transcript
Cloudflare Workers でGo のHTTP サー バーを動かすライブラリを作った話 syumai DP Engineering Monday
(2022/8/1)
自己紹介 syumai Go Documentation 輪読会 / ECMAScript 仕 様輪読会 主催
株式会社ベースマキナ所属 Go でGraphQL サーバー (gqlgen) や TypeScript でフロントエンドを書いています Twitter: @__syumai Website: https://syum.ai
話すこと Cloudflare Workers とは? syumai/workers の紹介 実装テクニックの紹介 syscall/js の処理など 現状の課題
example 集の紹介
Cloudflare Workers とは? Service Worker API ベースのJavaScript のWorker WebAssembly も実行可能
Cloudflare 経由のリクエストに割り込んで処理を行いレスポンスを返 せる 裏側にトラフィックを流すことなく、Worker が単独でレスポンスを組 み立てて返してもOK https://blog.cloudflare.com/ja-jp/cloudflare-workers-unleashed-ja- jp/#worker
Worker の例 Request を受け取って、Response を返す関数を書く形式 addEventListener("fetch", (event) => { event.respondWith(handleRequest(event.request));
}); async function handleRequest(request) { return new Response("Hello world"); } https://developers.cloudflare.com/workers/ より引用
Cloudflare Workers の機能 KV 分散 key / value store 結果整合
( 複数edge からの同一キーへの書き込みは後勝ち) Durable Objects edge 間でのデータ同期に使えるObject 強整合 Cache API ブラウザのキャッシュAPI のようなもの edge のキャッシュを操作出来る
Cloudflare Workers の用途の広がり 最近発表された新機能 ( まだ使えないものもあります) R2 S3 互換のオブジェクトストレージ D1
SQLite ベースの分散データベース Pub/Sub MQTT 互換のメッセージング基盤 => Cloudflare 上でフルスタックアプリケーションを作れる環境に近付い ている
syumai/workers の紹介
workers https://github.com/syumai/workers http.Handler を作って、 workers.Serve に渡すだけでCloudflare Workers 上でHTTP サーバーとして動作する 必要なツールはtinygo
とwrangler (Cloudflare Workers のCLI) だけ tinygo を使ってWebAssembly を生成して実行する JavaScript 側のコードを触る必要が無い Cloudflare の機能のバインディングを提供 (R2, KV)
workers を使ったコードのサンプル 普通に http.HandlerFunc を作るだけ func main() { handler :=
http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { name := req.URL.Query().Get("name") if name == "" { name = "world" } fmt.Fprintf(w, "Hello, %s!", name) }) workers.Serve(handler) } https://hello.syumai.workers.dev/?name=syumai (=> Hello, syumai と表示)
作ったモチベーション WebAssembly とJavaScript の知識が無くてもGo でWorker を書けるよ うにしたかった 最終的に、template のリポジトリをコピーして、Go のコードと
wrangler.toml を編集するだけで済む形になった https://github.com/syumai/worker-template-tinygo entrypoint としてJS のコードを含んでいるが、修正は不要 実用的なWorker を短時間で実装できるようなライブラリが欲しかった http.Handler のサポートで実現
workers package を使わなかった場合の例 Go とJS の2 ファイルでそれぞれ実装が必要 https://github.com/syumai/workers-playground/tree/main/tinygo-add
Go 側は、処理のexport が必要 export comment による関数export はtinygo の機能 package main
//export add func add(a, b int) int { return a + b } func main() {}
JS 側は、Go インスタンスの初期化、Wasm のロード、Worker の処理 の実装が必要 const go = new
Go(); const load = WebAssembly.instantiate(mod, go.importObject).then((instance) => { ... }); export default { async fetch(req) { const instance = await load; const url = new URL(req.url); const a = url.searchParams.get("a"); const b = url.searchParams.get("b"); if (a === null || b === null) { return new Response("invalid", { status: 400 }) } const result = `${a} + ${b} = ${instance.exports.add(a, b)}`; return new Response(result); }, };
実装テクニックの紹介
syumai/workers の基本的な実装形式 Cloudflare Workers は、基本的にRequest オブジェクトを処理し、 Response オブジェクトを返すと言う構造になっているため、下記が実 装できればOK JavaScript
側で受け取ったRequest オブジェクトをGo に渡す Go 側でResponse オブジェクトを組み立ててJavaScript 側に渡す これをGo の標準ライブラリのsyscall/js を使って実装した
紹介するもの 基本的な値の変換 バイト列の変換 Promise の待ち受け ストリームの変換
JS からGo への基本的な値の変換 Go のコード上で、JavaScript 側の値は、全て js.Value 型で扱われる js.Value のメソッドを使って値を変換、操作出来る
Go の基本的な型の値への変換 => Int() 、String() など Object やArray など、複雑なObject の操作 => Index() 、Set() 、Get() JavaScript 側のメソッド、関数の呼び出し => Call() 、Invoke()
Go からJS への基本的な値の変換 基本的に、ValueOf のルールに従って自動的に行われるため、実はあ まり考えなくていい JavaScript 側のnumber 型は浮動小数点数型なので精度に注意 |
Go | JavaScript | | ---------------------- | ---------------------- | | js.Value | [its value] | | js.Func | function | | nil | null | | bool | boolean | | integers and floats | number | | string | string | | []interface{} | new array | | map[string]interface{} | new object |
バイト列の変換 syscall/js の CopyBytesToGo / CopyBytesToJS 関数を使う Uint8Array と []byte
で相互にデータのコピーが可能 例 func (kv *kvNamespace) PutReader(key string, value io.Reader, opts *KVNamespacePutOptions) error { b, _ := io.ReadAll(value) ua := newUint8Array(len(b)) js.CopyBytesToJS(ua, b) p := kv.instance.Call("put", key, ua.Get("buffer"), opts.toJS()) return awaitPromise(p) }
Go からJS 側に値をコピーする時のテクニック コピー先のUint8Array がJavaScript 側に無い時は、Go 側から作る必要 がある (Value).New を使ってclass
のインスタンスを生成できるのでこれを使 う var uint8ArrayClass = global.Get("Uint8Array") func newUint8Array(size int) js.Value { return uint8ArrayClass.New(size) } https://github.com/syumai/workers/blob/v0.3.0/jsutil.go
ストリームの変換 JavaScript 側のコードがReadableStream を返した時、これを io.Reader として扱えるようにしたかった 逆もしかり deno_std のコードを参考に実装した https://github.com/syumai/workers/blob/v0.3.0/stream.go
後から気付いたが、Go の標準ライブラリにも同様の実装があったので これを使っても良かったかもしれない net/http/roudtrip_js.go
Promise の待ち受け Go から呼んだJavaScript 側の関数がPromise を返す時、Go 側のコード がブロックされない Promise を待ち受けるための処理はsyscall/js
では提供されていない 自前でchannel を使って書く必要がある
then とcatch を呼んでchannel に送信、select 文で待ち受けreturn func awaitPromise(promiseVal js.Value) (js.Value, error)
{ resultCh := make(chan js.Value) errCh := make(chan error) var then, catch js.Func then = js.FuncOf(func(_ js.Value, args []js.Value) any { defer then.Release() result := args[0] resultCh <- result return js.Undefined() }) catch = js.FuncOf(func(_ js.Value, args []js.Value) any { defer catch.Release() result := args[0] errCh <- fmt.Errorf("failed on promise: %s", result.Call("toString").String()) return js.Undefined() }) promiseVal.Call("then", then).Call("catch", catch) select { case result := <-resultCh: return result, nil case err := <-errCh: return js.Value{}, err } }
現状の課題
ファイルサイズ制限 圧縮後のサイズが1MB 以内でないといけない制約があるため、バイナ リサイズが大きくなる通常のGo ではpublish に失敗した 実はtinygo でもギリギリで、依存ライブラリを増やすと簡単に越える
tinygo でencoding/json が動かない tinygo のreflect の実装が完全でないため、encoding/json が動かない easyjson などの別のJSON encoder
/ decoder を使う必要がある
tinygo でnet/http のHTTP Client が動かない tinygo を使った場合、Worker 上でhttp.Get などが動かないため、プロ キシ用途で使うことが出来ない
一応回避策を見つけて、ベーシック認証プロキシを作ることに成功し た https://github.com/syumai/workers/tree/v0.3.0/examples/basic- auth-proxy tinygo 0.24.0 で動かなくなってしまったが、takasago さんの修正で 0.25.0 でまた動くようになるはず https://github.com/tinygo-org/tinygo/pull/3036
example 集 JSON API サーバー R2 を使った画像アップロード / 配信サーバー KV
を使ったアクセスカウンター ぜひ、template リポジトリからWorker を作ってpublish してみてくださ い https://github.com/syumai/worker-template-tinygo
発表内容について Zenn の方にも記事を投稿しているので、興味があればぜひご覧ください Cloudflare Workers で簡単にGo のHTTP サーバーを動かすためのライ ブラリを作った https://zenn.dev/syumai/articles/ca9n4e91eqljc44k6ebg
ご清聴ありがとうございました!