Skip to content

Commit

Permalink
Merge pull request #36 from aki-0421/fetch-event
Browse files Browse the repository at this point in the history
Full support for FetchEvent
  • Loading branch information
syumai committed Apr 21, 2023
2 parents cd76e88 + a867a2d commit 086a224
Show file tree
Hide file tree
Showing 14 changed files with 135 additions and 75 deletions.
5 changes: 1 addition & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
20 changes: 17 additions & 3 deletions cloudflare/fetchevent.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -23,3 +22,18 @@ 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)
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()
})))
}
File renamed without changes.
13 changes: 13 additions & 0 deletions examples/fetch-event/Makefile
Original file line number Diff line number Diff line change
@@ -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
48 changes: 48 additions & 0 deletions examples/fetch-event/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# [FetchEvent](https://developers.cloudflare.com/workers/runtime-apis/fetch-event/)

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.

#### WaitUntil

`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 = "sub.example.com/*", zone_name = "example.com" }
]
```

The workers is executed if the URL matches `sub.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
```
File renamed without changes.
File renamed without changes.
46 changes: 46 additions & 0 deletions examples/fetch-event/main.go
Original file line number Diff line number Diff line change
@@ -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))
}
File renamed without changes.
10 changes: 10 additions & 0 deletions examples/fetch-event/wrangler.toml
Original file line number Diff line number Diff line change
@@ -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"
12 changes: 0 additions & 12 deletions examples/wait-until/Makefile

This file was deleted.

25 changes: 0 additions & 25 deletions examples/wait-until/README.md

This file was deleted.

25 changes: 0 additions & 25 deletions examples/wait-until/main.go

This file was deleted.

6 changes: 0 additions & 6 deletions examples/wait-until/wrangler.toml

This file was deleted.

0 comments on commit 086a224

Please sign in to comment.