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

Adding support for Init Functions #65

Merged
merged 2 commits into from
Oct 1, 2023
Merged
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ build: build-testdata

build-testdata:
$(MAKE) -C testdata/default build
$(MAKE) -C testdata/fail build
$(MAKE) -C testdata/kv build
$(MAKE) -C testdata/sql build
$(MAKE) -C testdata/logger build
Expand Down
20 changes: 20 additions & 0 deletions docs/wasm-functions/multi-function-services.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,26 @@ Here is an example of a route object that defines a scheduled task that executes

You can define multiple scheduled tasks in the routes array.

##### Init Functions

In addition to HTTP and scheduled task routes, Tarmac also supports init functions.

You can define an init function route by adding a route object with the following properties to the routes array:

- `type` (required): For Init Functions, set to `init`.
- `function` (required): The function to call when the service is initialized.

Here is an example of a route object that defines an init function that executes the default function when the service is initialized:

```json
{
"type": "init",
"function": "default"
}
```

You can define multiple init functions in the routes array. Functions will be executed before the server is fully started but after the WASM modules are loaded and callbacks are registered.

##### Functions

Tarmac supports the ability for Functions to call other Functions using the Function to Function route.
Expand Down
19 changes: 18 additions & 1 deletion pkg/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,14 @@
// Register Routes
srv.log.Infof("Registering Routes from Service %s", svcName)
funcRoutes := make(map[string]string)
initRoutes := []string{}
for _, r := range svcCfg.Routes {
// Copy init functions for later execution
if r.Type == "init" {
initRoutes = append(initRoutes, r.Function)
}

// Register HTTP based functions with the HTTP router
if r.Type == "http" {
for _, m := range r.Methods {
key := fmt.Sprintf("%s:%s:%s", r.Type, m, r.Path)
Expand All @@ -464,6 +471,7 @@
}
}

// Schedule tasks for scheduled functions
if r.Type == "scheduled_task" {
srv.log.Infof("Scheduling custom task for function %s with interval of %d", r.Function, r.Frequency)
id, err := srv.scheduler.Add(&tasks.Task{
Expand All @@ -488,15 +496,24 @@
defer srv.scheduler.Del(id)
}

// Setup callbacks for function to function calls
if r.Type == "function" {
srv.log.Infof("Registering Function to Function callback for %s", r.Function)
router.RegisterCallback("function", r.Function, func(b []byte) ([]byte, error) {
return srv.runWASM(r.Function, "handler", b)
})
}
}
}

// Execute init functions
for _, f := range initRoutes {
srv.log.Infof("Executing Init Function %s", f)
_, err := srv.runWASM(f, "handler", []byte(""))
if err != nil {
return fmt.Errorf("error executing init function %s - %s", f, err)
}

Check warning on line 514 in pkg/app/app.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/app.go#L513-L514

Added lines #L513 - L514 were not covered by tests
madflojo marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

// Register Metrics Handler
Expand Down
9 changes: 9 additions & 0 deletions pkg/app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ func TestBadConfigs(t *testing.T) {
v.Set("wasm_function", "something-that-does-not-exist")
cfgs["invalid WASM path"] = v

// Failing init function
v = viper.New()
v.Set("enable_tls", false)
v.Set("listen_addr", "0.0.0.0:8443")
v.Set("disable_logging", true)
v.Set("enable_kvstore", false)
v.Set("wasm_function_config", "/testdata/tarmac-fail.json")
cfgs["failing init function"] = v

// Loop through bad configs, creating sub-tests as we go
for k, v := range cfgs {
t.Run("Testing "+k, func(t *testing.T) {
Expand Down
10 changes: 10 additions & 0 deletions testdata/fail/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## Makefile for Go example for Tarmac WASM functions

build:
## Run TinyGo build via Docker because its easier
docker run --rm -v `pwd`:/build -w /build tinygo/tinygo:0.25.0 tinygo build -o /build/tarmac.wasm -target wasi /build/main.go

docker-compose:
docker compose up

run: build docker-compose
12 changes: 12 additions & 0 deletions testdata/fail/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: '3.8'
services:
tarmac-example:
image: madflojo/tarmac
ports:
- 80:8080
environment:
- "APP_ENABLE_TLS=false"
- "APP_LISTEN_ADDR=0.0.0.0:8080"
- "APP_DEBUG=true"
volumes:
- "./:/functions"
10 changes: 10 additions & 0 deletions testdata/fail/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module github.com/tarmac-project/tarmac/testdata/fail

go 1.21

require github.com/tarmac-project/tarmac/pkg/sdk v0.5.0

require (
github.com/valyala/fastjson v1.6.4 // indirect
github.com/wapc/wapc-guest-tinygo v0.3.3 // indirect
)
8 changes: 8 additions & 0 deletions testdata/fail/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 h1:xoIK0ctDddBMnc74udxJYBqlo9Ylnsp1waqjLsnef20=
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
github.com/tarmac-project/tarmac/pkg/sdk v0.5.0 h1:QKsEf6SXTYrJM9/B4cNoM4RS3/rzuViJaiutEcdSRZQ=
github.com/tarmac-project/tarmac/pkg/sdk v0.5.0/go.mod h1:UTKYV0QFdkJDgV2sJcnuCujVy49MCd8bgi2JmwviJ6E=
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
github.com/wapc/wapc-guest-tinygo v0.3.3 h1:jLebiwjVSHLGnS+BRabQ6+XOV7oihVWAc05Hf1SbeR0=
github.com/wapc/wapc-guest-tinygo v0.3.3/go.mod h1:mzM3CnsdSYktfPkaBdZ8v88ZlfUDEy5Jh5XBOV3fYcw=
20 changes: 20 additions & 0 deletions testdata/fail/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// This program is a test program used to facilitate unit testing with Tarmac.
package main

import (
"fmt"
"github.com/tarmac-project/tarmac/pkg/sdk"
)

func main() {
// Initialize the Tarmac SDK
_, err := sdk.New(sdk.Config{Namespace: "test-service", Handler: Handler})
if err != nil {
return
}
}

func Handler(payload []byte) ([]byte, error) {
// Return a happy message
return []byte(""), fmt.Errorf("This is a test error")
}
18 changes: 18 additions & 0 deletions testdata/tarmac-fail.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"services": {
"test-service": {
"name": "test-service",
"functions": {
"fail": {
"filepath": "/testdata/fail/tarmac.wasm"
}
},
"routes": [
{
"type": "init",
"function": "fail"
}
]
}
}
}
4 changes: 4 additions & 0 deletions testdata/tarmac.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
}
},
"routes": [
{
"type": "init",
"function": "default"
},
{
"type": "http",
"path": "/",
Expand Down