From a9fa5503715b9af666d35525317ffbba6dc1439c Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Thu, 20 Apr 2023 07:57:04 +0900 Subject: [PATCH 1/5] F: add passThroughOnException --- cloudflare/fetchevent.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/cloudflare/fetchevent.go b/cloudflare/fetchevent.go index 9fa64ce..a4ff375 100644 --- a/cloudflare/fetchevent.go +++ b/cloudflare/fetchevent.go @@ -12,9 +12,8 @@ import ( // It accepts an asynchronous task which the Workers runtime will execute before the handler terminates but without blocking the response. // see: https://developers.cloudflare.com/workers/runtime-apis/fetch-event/#waituntil func WaitUntil(ctx context.Context, task func()) { - executionContext := cfruntimecontext.GetExecutionContext(ctx) - - executionContext.Call("waitUntil", jsutil.NewPromise(js.FuncOf(func(this js.Value, pArgs []js.Value) any { + exCtx := cfruntimecontext.GetExecutionContext(ctx) + exCtx.Call("waitUntil", jsutil.NewPromise(js.FuncOf(func(this js.Value, pArgs []js.Value) any { resolve := pArgs[0] go func() { task() @@ -23,3 +22,11 @@ func WaitUntil(ctx context.Context, task func()) { return js.Undefined() }))) } + +// PassThroughOnException prevents a runtime error response when the Worker script throws an unhandled exception. +// Instead, the request forwards to the origin server as if it had not gone through the worker. +// see: https://developers.cloudflare.com/workers/runtime-apis/fetch-event/#passthroughonexception +func PassThroughOnException(ctx context.Context) { + exCtx := cfruntimecontext.GetExecutionContext(ctx) + exCtx.Call("passThroughOnException") +} From 985be71fa87a4e7c71803b90b8e6cd797723c95a Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Thu, 20 Apr 2023 07:57:24 +0900 Subject: [PATCH 2/5] R: remove wait-until example --- examples/wait-until/.gitignore | 1 - examples/wait-until/Makefile | 12 ------------ examples/wait-until/README.md | 25 ------------------------- examples/wait-until/go.mod | 7 ------- examples/wait-until/go.sum | 2 -- examples/wait-until/main.go | 25 ------------------------- examples/wait-until/worker.mjs | 22 ---------------------- examples/wait-until/wrangler.toml | 6 ------ 8 files changed, 100 deletions(-) delete mode 100644 examples/wait-until/.gitignore delete mode 100644 examples/wait-until/Makefile delete mode 100644 examples/wait-until/README.md delete mode 100644 examples/wait-until/go.mod delete mode 100644 examples/wait-until/go.sum delete mode 100644 examples/wait-until/main.go delete mode 100644 examples/wait-until/worker.mjs delete mode 100644 examples/wait-until/wrangler.toml diff --git a/examples/wait-until/.gitignore b/examples/wait-until/.gitignore deleted file mode 100644 index 53c37a1..0000000 --- a/examples/wait-until/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist \ No newline at end of file diff --git a/examples/wait-until/Makefile b/examples/wait-until/Makefile deleted file mode 100644 index 320ddc3..0000000 --- a/examples/wait-until/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -.PHONY: dev -dev: - wrangler dev - -.PHONY: build -build: - mkdir -p dist - tinygo build -o ./dist/app.wasm -target wasm ./... - -.PHONY: publish -publish: - wrangler publish diff --git a/examples/wait-until/README.md b/examples/wait-until/README.md deleted file mode 100644 index 8b27649..0000000 --- a/examples/wait-until/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# wait-until - -* Executes a task in worker even after the server has returned the response. -* This example executes 5-second task after responding and outputs the console log. - -## Document - -* https://developers.cloudflare.com/workers/runtime-apis/fetch-event/#waituntil - -## Development - -### Requirements - -This project requires these tools to be installed globally. - -* wrangler -* tinygo - -### Commands - -``` -make dev # run dev server -make build # build Go Wasm binary -make publish # publish worker -``` diff --git a/examples/wait-until/go.mod b/examples/wait-until/go.mod deleted file mode 100644 index 8a8adaa..0000000 --- a/examples/wait-until/go.mod +++ /dev/null @@ -1,7 +0,0 @@ -module github.com/syumai/hello - -go 1.18 - -require github.com/syumai/workers v0.0.0 - -replace github.com/syumai/workers => ../../ \ No newline at end of file diff --git a/examples/wait-until/go.sum b/examples/wait-until/go.sum deleted file mode 100644 index 8c27871..0000000 --- a/examples/wait-until/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -github.com/syumai/workers v0.1.0 h1:z5QfQR2X+PCKzom7RodpI5J4D5YF7NT7Qwzb9AM9dgY= -github.com/syumai/workers v0.1.0/go.mod h1:alXIDhTyeTwSzh0ZgQ3cb9HQPyyYfIejupE4Z3efr14= diff --git a/examples/wait-until/main.go b/examples/wait-until/main.go deleted file mode 100644 index c93d51a..0000000 --- a/examples/wait-until/main.go +++ /dev/null @@ -1,25 +0,0 @@ -package main - -import ( - "fmt" - "net/http" - "time" - - "github.com/syumai/workers" - "github.com/syumai/workers/cloudflare" -) - -func main() { - handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - cloudflare.WaitUntil(req.Context(), func() { - for i := 0; i < 5; i++ { - time.Sleep(time.Second) - } - - fmt.Println("5-second task completed") - }) - - w.Write([]byte("http response done")) - }) - workers.Serve(handler) -} diff --git a/examples/wait-until/worker.mjs b/examples/wait-until/worker.mjs deleted file mode 100644 index 649ccf0..0000000 --- a/examples/wait-until/worker.mjs +++ /dev/null @@ -1,22 +0,0 @@ -import "../assets/polyfill_performance.js"; -import "../assets/wasm_exec.js"; -import mod from "./dist/app.wasm"; - -const go = new Go(); - -const readyPromise = new Promise((resolve) => { - globalThis.ready = resolve; -}); - -const load = WebAssembly.instantiate(mod, go.importObject).then((instance) => { - go.run(instance); - return instance; -}); - -export default { - async fetch(req, env, ctx) { - await load; - await readyPromise; - return handleRequest(req, { env, ctx }); - } -} diff --git a/examples/wait-until/wrangler.toml b/examples/wait-until/wrangler.toml deleted file mode 100644 index 7c941bc..0000000 --- a/examples/wait-until/wrangler.toml +++ /dev/null @@ -1,6 +0,0 @@ -name = "wait-until" -main = "./worker.mjs" -compatibility_date = "2023-02-24" - -[build] -command = "make build" From f47632578f92c3de0ccb1d5d976cdb7687979b7f Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Thu, 20 Apr 2023 08:13:19 +0900 Subject: [PATCH 3/5] F: add fetch-event example --- examples/fetch-event/.gitignore | 1 + examples/fetch-event/Makefile | 13 +++++++++ examples/fetch-event/README.md | 30 +++++++++++++++++++ examples/fetch-event/go.mod | 7 +++++ examples/fetch-event/go.sum | 2 ++ examples/fetch-event/main.go | 46 ++++++++++++++++++++++++++++++ examples/fetch-event/worker.mjs | 22 ++++++++++++++ examples/fetch-event/wrangler.toml | 10 +++++++ 8 files changed, 131 insertions(+) create mode 100644 examples/fetch-event/.gitignore create mode 100644 examples/fetch-event/Makefile create mode 100644 examples/fetch-event/README.md create mode 100644 examples/fetch-event/go.mod create mode 100644 examples/fetch-event/go.sum create mode 100644 examples/fetch-event/main.go create mode 100644 examples/fetch-event/worker.mjs create mode 100644 examples/fetch-event/wrangler.toml diff --git a/examples/fetch-event/.gitignore b/examples/fetch-event/.gitignore new file mode 100644 index 0000000..53c37a1 --- /dev/null +++ b/examples/fetch-event/.gitignore @@ -0,0 +1 @@ +dist \ No newline at end of file diff --git a/examples/fetch-event/Makefile b/examples/fetch-event/Makefile new file mode 100644 index 0000000..11a0197 --- /dev/null +++ b/examples/fetch-event/Makefile @@ -0,0 +1,13 @@ +.PHONY: dev +dev: + wrangler dev + +.PHONY: build +build: + mkdir -p dist + #tinygo build -o ./dist/app.wasm -target wasm ./... + tinygo build -o ./dist/app.wasm -target wasm -no-debug ./... + +.PHONY: publish +publish: + wrangler publish diff --git a/examples/fetch-event/README.md b/examples/fetch-event/README.md new file mode 100644 index 0000000..861afef --- /dev/null +++ b/examples/fetch-event/README.md @@ -0,0 +1,30 @@ +# fetch-event + +## Document + +* https://developers.cloudflare.com/workers/runtime-apis/fetch-event/ + +## Setup + +```toml +routes = [ + { pattern = "example.com/*", zone_name = "example.com" } +] +``` + +## Development + +### Requirements + +This project requires these tools to be installed globally. + +* wrangler +* tinygo + +### Commands + +``` +make dev # run dev server +make build # build Go Wasm binary +make publish # publish worker +``` diff --git a/examples/fetch-event/go.mod b/examples/fetch-event/go.mod new file mode 100644 index 0000000..8a8adaa --- /dev/null +++ b/examples/fetch-event/go.mod @@ -0,0 +1,7 @@ +module github.com/syumai/hello + +go 1.18 + +require github.com/syumai/workers v0.0.0 + +replace github.com/syumai/workers => ../../ \ No newline at end of file diff --git a/examples/fetch-event/go.sum b/examples/fetch-event/go.sum new file mode 100644 index 0000000..8c27871 --- /dev/null +++ b/examples/fetch-event/go.sum @@ -0,0 +1,2 @@ +github.com/syumai/workers v0.1.0 h1:z5QfQR2X+PCKzom7RodpI5J4D5YF7NT7Qwzb9AM9dgY= +github.com/syumai/workers v0.1.0/go.mod h1:alXIDhTyeTwSzh0ZgQ3cb9HQPyyYfIejupE4Z3efr14= diff --git a/examples/fetch-event/main.go b/examples/fetch-event/main.go new file mode 100644 index 0000000..4e56a84 --- /dev/null +++ b/examples/fetch-event/main.go @@ -0,0 +1,46 @@ +package main + +import ( + "fmt" + "net/http" + "net/http/httputil" + "time" + + "github.com/syumai/workers" + "github.com/syumai/workers/cloudflare" + "github.com/syumai/workers/cloudflare/fetch" +) + +func handler(w http.ResponseWriter, req *http.Request) { + ctx := req.Context() + + cloudflare.PassThroughOnException(ctx) + + // logging after responding + cloudflare.WaitUntil(ctx, func() { + for i := 0; i < 5; i++ { + time.Sleep(time.Second) + } + fmt.Println("5-second task completed") + }) + + // panic if x-error header has provided + if req.Header.Get("x-error") != "" { + panic("error") + } + + // responds with origin server + fc := fetch.NewClient() + proxy := httputil.ReverseProxy{ + Transport: fc.HTTPClient().Transport, + Director: func(r *http.Request) { + r.URL = req.URL + }, + } + + proxy.ServeHTTP(w, req) +} + +func main() { + workers.Serve(http.HandlerFunc(handler)) +} diff --git a/examples/fetch-event/worker.mjs b/examples/fetch-event/worker.mjs new file mode 100644 index 0000000..649ccf0 --- /dev/null +++ b/examples/fetch-event/worker.mjs @@ -0,0 +1,22 @@ +import "../assets/polyfill_performance.js"; +import "../assets/wasm_exec.js"; +import mod from "./dist/app.wasm"; + +const go = new Go(); + +const readyPromise = new Promise((resolve) => { + globalThis.ready = resolve; +}); + +const load = WebAssembly.instantiate(mod, go.importObject).then((instance) => { + go.run(instance); + return instance; +}); + +export default { + async fetch(req, env, ctx) { + await load; + await readyPromise; + return handleRequest(req, { env, ctx }); + } +} diff --git a/examples/fetch-event/wrangler.toml b/examples/fetch-event/wrangler.toml new file mode 100644 index 0000000..60e0df1 --- /dev/null +++ b/examples/fetch-event/wrangler.toml @@ -0,0 +1,10 @@ +name = "fetch-event" +main = "./worker.mjs" +compatibility_date = "2023-02-24" + +routes = [ + { pattern = "example.com/*", zone_name = "example.com" } +] + +[build] +command = "make build" From 1e152e5743117a1534da3ae9b191253b385f70e7 Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Thu, 20 Apr 2023 11:53:07 +0900 Subject: [PATCH 4/5] F: update readme --- README.md | 5 +---- examples/fetch-event/README.md | 36 +++++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 37818c1..8c5e128 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,7 @@ - [x] Calling stubs * [x] D1 (alpha) * [x] Environment variables -* FetchEvent's [lifecycle methods](https://developers.cloudflare.com/workers/runtime-apis/fetch-event/#lifecycle-methods) - - [x] waitUntil - - [ ] respondWith - - [ ] passThroughOnException +* [x] FetchEvent ## Installation diff --git a/examples/fetch-event/README.md b/examples/fetch-event/README.md index 861afef..40923eb 100644 --- a/examples/fetch-event/README.md +++ b/examples/fetch-event/README.md @@ -1,30 +1,48 @@ -# fetch-event +# [FetchEvent](https://developers.cloudflare.com/workers/runtime-apis/fetch-event/) -## Document +Normally, workers are designed to return some kind of HTTP Response and exit immediately upon receiving an HTTP request. `FetchEvent` can extend these life cycles. -* https://developers.cloudflare.com/workers/runtime-apis/fetch-event/ +#### WaitUntil -## Setup +`WaitUntil` extends the lifetime of the "fetch" event. It accepts an asynchronous task which the Workers runtime will execute without blocking the response. The worker will not be terminated until those tasks are completed. + +#### PassThroughOnException + +`PassThroughOnException` prevents a runtime error response when the Worker script throws an unhandled exception. Instead, the request forwards to the origin server as if it had not gone through the worker. + +## Example + +### Usecase + +You have decided to implement a log stream API to capture all access logs. You must edit the Headers so that the user's API token is not logged. If an unknown error occurs during this process, the entire service will be down, which must be avoided. +In such cases, declare PassThroughOnException first and use WaitUntil for logging. + +### Setup + +This example worker is triggered by [Routes](https://developers.cloudflare.com/workers/platform/triggers/routes/). To try this example, add your site to cloudflare and add some records(A and CNAME, etc.) so that you can actually access the website. +If your domain is `sub.example.com`, edit `wrangler.toml` as following: ```toml routes = [ - { pattern = "example.com/*", zone_name = "example.com" } + { pattern = "sub.example.com/*", zone_name = "example.com" } ] ``` -## Development +The workers is executed if the URL matches `sub.example.com/*`. -### Requirements +### Development + +#### Requirements This project requires these tools to be installed globally. * wrangler * tinygo -### Commands +#### Commands ``` make dev # run dev server make build # build Go Wasm binary make publish # publish worker -``` +``` \ No newline at end of file From a867a2dcbf0274b37d276b580a2d577c3103d4f7 Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Thu, 20 Apr 2023 21:29:18 +0900 Subject: [PATCH 5/5] R: fix 500 error bug --- cloudflare/fetchevent.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cloudflare/fetchevent.go b/cloudflare/fetchevent.go index a4ff375..2c63db7 100644 --- a/cloudflare/fetchevent.go +++ b/cloudflare/fetchevent.go @@ -28,5 +28,12 @@ func WaitUntil(ctx context.Context, task func()) { // see: https://developers.cloudflare.com/workers/runtime-apis/fetch-event/#passthroughonexception func PassThroughOnException(ctx context.Context) { exCtx := cfruntimecontext.GetExecutionContext(ctx) - exCtx.Call("passThroughOnException") + jsutil.AwaitPromise(jsutil.NewPromise(js.FuncOf(func(this js.Value, pArgs []js.Value) any { + resolve := pArgs[0] + go func() { + exCtx.Call("passThroughOnException") + resolve.Invoke(js.Undefined()) + }() + return js.Undefined() + }))) }