Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

split Done funcs from workers.Serve / cron.ScheduleTask #132

Merged
merged 6 commits into from
Nov 7, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion _examples/cron/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.PHONY: dev
dev:
wrangler dev
wrangler dev --test-scheduled

.PHONY: build
build:
9 changes: 9 additions & 0 deletions _examples/cron/README.md
Original file line number Diff line number Diff line change
@@ -18,3 +18,12 @@ make dev # run dev server
make build # build Go Wasm binary
make deploy # deploy worker
```

#### Testing cron schedule

* With curl command below, you can test the cron schedule.
- see: https://developers.cloudflare.com/workers/runtime-apis/handlers/scheduled/#background

```
curl "http://localhost:8787/__scheduled?cron=*+*+*+*+*"
```
7 changes: 7 additions & 0 deletions _examples/cron/main.go
Original file line number Diff line number Diff line change
@@ -3,7 +3,9 @@ package main
import (
"context"
"fmt"
"time"

"github.com/syumai/workers/cloudflare"
"github.com/syumai/workers/cloudflare/cron"
)

@@ -15,6 +17,11 @@ func task(ctx context.Context) error {

fmt.Println(e.ScheduledTime.Unix())

cloudflare.WaitUntil(func() {
time.Sleep(1 * time.Second)
fmt.Println("Run sub task after returning from main task")
})

return nil
}

3 changes: 3 additions & 0 deletions _examples/multiple-handlers/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
build
node_modules
.wrangler
12 changes: 12 additions & 0 deletions _examples/multiple-handlers/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.PHONY: dev
dev:
wrangler dev --test-scheduled

.PHONY: build
build:
go run ../../cmd/workers-assets-gen
tinygo build -o ./build/app.wasm -target wasm -no-debug ./...

.PHONY: deploy
deploy:
wrangler deploy
29 changes: 29 additions & 0 deletions _examples/multiple-handlers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# multiple-handlers

* This example shows how to use multiple handlers in a single worker.

## 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 deploy # deploy worker
```

#### Testing cron schedule

* With curl command below, you can test the cron schedule.
- see: https://developers.cloudflare.com/workers/runtime-apis/handlers/scheduled/#background

```
curl "http://localhost:8787/__scheduled?cron=*+*+*+*+*"
```
7 changes: 7 additions & 0 deletions _examples/multiple-handlers/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module github.com/syumai/workers/_examples/multiple-handlers

go 1.21.3

require github.com/syumai/workers v0.0.0

replace github.com/syumai/workers => ../../
Empty file.
38 changes: 38 additions & 0 deletions _examples/multiple-handlers/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package main

import (
"context"
"fmt"
"net/http"

"github.com/syumai/workers"
"github.com/syumai/workers/cloudflare/cron"
)

func main() {
handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
fmt.Fprint(w, "Hello, world!")
})

task := func(ctx context.Context) error {
e, err := cron.NewEvent(ctx)
if err != nil {
return err
}
fmt.Println(e.ScheduledTime.Unix())
return nil
}

// set up the worker
workers.ServeNonBlock(handler)
cron.ScheduleTaskNonBlock(task)

// send a ready signal to the runtime
workers.Ready()

// block until the handler or task is done
select {
case <-workers.Done():
case <-cron.Done():
}
}
10 changes: 10 additions & 0 deletions _examples/multiple-handlers/wrangler.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name = "multiple-handlers"
main = "./build/worker.mjs"
compatibility_date = "2023-02-24"
workers_dev = false

[triggers]
crons = ["* * * * *"]

[build]
command = "make build"
23 changes: 16 additions & 7 deletions cloudflare/cron/scheduler.go
Original file line number Diff line number Diff line change
@@ -5,13 +5,17 @@ import (
"fmt"
"syscall/js"

"github.com/syumai/workers"
"github.com/syumai/workers/internal/jsutil"
"github.com/syumai/workers/internal/runtimecontext"
)

type Task func(ctx context.Context) error

var scheduledTask Task
var (
scheduledTask Task
doneCh = make(chan struct{})
)

func runScheduler(eventObj js.Value) error {
ctx := runtimecontext.New(context.Background(), eventObj)
@@ -46,16 +50,21 @@ func init() {
jsutil.Binding.Set("runScheduler", runSchedulerCallback)
}

//go:wasmimport workers ready
func ready()

// ScheduleTask sets the Task to be executed
func ScheduleTask(task Task) {
scheduledTask = task
ready()
select {}
workers.Ready()
<-Done()
}

// ScheduleTaskNonBlock sets the Task to be executed but does not signal readiness or block
// indefinitely. The non-blocking form is meant to be used in conjunction with [workers.Serve].
func ScheduleTaskNonBlock(task Task) { scheduledTask = task }
func ScheduleTaskNonBlock(task Task) {
scheduledTask = task
}

// Done returns a channel which is closed when the task is done.
// Currently, this channel is never closed to support cloudflare.WaitUntil feature.
func Done() <-chan struct{} {
return doneCh
}
12 changes: 12 additions & 0 deletions handler.go
Original file line number Diff line number Diff line change
@@ -25,3 +25,15 @@ func Serve(handler http.Handler) {
fmt.Fprintln(os.Stderr, "warn: this server is currently running in non-JS mode. to enable JS-related features, please use the make command in the syumai/workers template.")
http.ListenAndServe(addr, handler)
}

func ServeNonBlock(http.Handler) {
panic("ServeNonBlock is not supported in non-JS environments")
}

func Ready() {
panic("Ready is not supported in non-JS environments")
}

func Done() <-chan struct{} {
panic("Done is not supported in non-JS environments")
}
30 changes: 23 additions & 7 deletions handler_js.go
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ import (

var (
httpHandler http.Handler
closeCh = make(chan struct{})
doneCh = make(chan struct{})
)

func init() {
@@ -52,7 +52,7 @@ type appCloser struct {
}

func (c *appCloser) Close() error {
defer close(closeCh)
defer close(doneCh)
return c.ReadCloser.Close()
}

@@ -84,16 +84,32 @@ func handleRequest(reqObj js.Value) (js.Value, error) {
return w.ToJSResponse(), nil
}

//go:wasmimport workers ready
func ready()

// Server serves http.Handler on a JS runtime.
// Serve serves http.Handler on a JS runtime.
// if the given handler is nil, http.DefaultServeMux will be used.
func Serve(handler http.Handler) {
ServeNonBlock(handler)
Ready()
<-Done()
}

// ServeNonBlock sets the http.Handler to be served but does not signal readiness or block
// indefinitely. The non-blocking form is meant to be used in conjunction with Ready and WaitForCompletion.
func ServeNonBlock(handler http.Handler) {
if handler == nil {
handler = http.DefaultServeMux
}
httpHandler = handler
}

//go:wasmimport workers ready
func ready()

// Ready must be called after all setups of the Go side's handlers are done.
func Ready() {
ready()
<-closeCh
}

// Done returns a channel which is closed when the handler is done.
func Done() <-chan struct{} {
return doneCh
}
Loading