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

feat: add priority to modules #1002

Merged
merged 9 commits into from
Aug 6, 2024
3 changes: 2 additions & 1 deletion router-tests/modules/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package module_test

import (
"encoding/json"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/wundergraph/cosmo/router-tests/testenv"
"testing"

"github.com/wundergraph/cosmo/router/cmd/custom/module"
"github.com/wundergraph/cosmo/router/core"
Expand Down
2 changes: 2 additions & 0 deletions router/cmd/custom/module/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ func (m *MyModule) Module() core.ModuleInfo {
return core.ModuleInfo{
// This is the ID of your module, it must be unique
ID: myModuleID,
// The priority of your module, lower numbers are executed first
Priority: 1,
New: func() core.Module {
return &MyModule{}
},
Expand Down
31 changes: 30 additions & 1 deletion router/core/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package core
import (
stdContext "context"
"fmt"
"math"
"net/http"
"sort"
"sync"

"github.com/pkg/errors"
Expand Down Expand Up @@ -39,7 +41,8 @@ type ModuleID string

type ModuleInfo struct {
// Name is the name of the module
ID ModuleID
ID ModuleID
Priority int
// New is the function that creates a new instance of the module
New func() Module
}
Expand Down Expand Up @@ -67,6 +70,32 @@ func RegisterModule(instance Module) {
modules[string(mod.ID)] = mod
}

// sortModules sorts the modules by priority
func sortModules(modules map[string]ModuleInfo) []ModuleInfo {
var moduleList []ModuleInfo
for _, module := range modules {
moduleList = append(moduleList, module)
}

sort.Slice(moduleList, func(x, y int) bool {
priorityX := moduleList[x].Priority
priorityY := moduleList[y].Priority
leastPriority := math.MaxInt

// If priority is 0, treat it as the lowest possible value
if priorityX == 0 {
priorityX = leastPriority
}
if priorityY == 0 {
priorityY = leastPriority
}

return priorityX < priorityY
})

return moduleList
}

// Module Interfaces

// RouterMiddlewareHandler allows you to add a middleware to the router.
Expand Down
85 changes: 85 additions & 0 deletions router/core/modules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package core

import (
"errors"
"github.com/stretchr/testify/assert"
"io"
"net/http/httptest"
"testing"
Expand Down Expand Up @@ -51,3 +52,87 @@ func TestSingleError(t *testing.T) {

require.Equal(t, `{"errors":[{"message":"test"}],"data":null}`, string(body))
}

func TestSortingModulesByPriority(t *testing.T) {
modulesW := make(map[string]ModuleInfo)
modulesW["module1_0"] = ModuleInfo{
ID: "module1_0",
New: func() Module {
return nil
},
}
modulesW["module2_0"] = ModuleInfo{
ID: "module2_0",
New: func() Module {
return nil
},
}

modulesX := make(map[string]ModuleInfo)
modulesX["module1_1"] = ModuleInfo{
ID: "module1_1",
Priority: 1,
New: func() Module {
return nil
},
}
modulesX["module2_2"] = ModuleInfo{
ID: "module2_2",
Priority: 2,
New: func() Module {
return nil
},
}

modulesY := make(map[string]ModuleInfo)
modulesY["module1_2"] = ModuleInfo{
ID: "module1_2",
Priority: 2,
New: func() Module {
return nil
},
}
modulesY["module2_1"] = ModuleInfo{
ID: "module2_1",
Priority: 1,
New: func() Module {
return nil
},
}

modulesZ := make(map[string]ModuleInfo)
modulesZ["module1_0"] = ModuleInfo{
ID: "module1_0",
New: func() Module {
return nil
},
}
modulesZ["module2_2"] = ModuleInfo{
ID: "module2_2",
Priority: 2,
New: func() Module {
return nil
},
}

sortedModulesW := sortModules(modulesW)
assert.Equal(t, 2, len(sortedModulesW))

sortedModulesX := sortModules(modulesX)
assert.Equal(t, ModuleID("module1_1"), sortedModulesX[0].ID)
assert.Equal(t, 1, sortedModulesX[0].Priority)
assert.Equal(t, ModuleID("module2_2"), sortedModulesX[1].ID)
assert.Equal(t, 2, sortedModulesX[1].Priority)

sortedModulesY := sortModules(modulesY)
assert.Equal(t, ModuleID("module2_1"), sortedModulesY[0].ID)
assert.Equal(t, 1, sortedModulesY[0].Priority)
assert.Equal(t, ModuleID("module1_2"), sortedModulesY[1].ID)
assert.Equal(t, 2, sortedModulesY[1].Priority)

sortedModulesZ := sortModules(modulesZ)
assert.Equal(t, ModuleID("module2_2"), sortedModulesZ[0].ID)
assert.Equal(t, 2, sortedModulesZ[0].Priority)
assert.Equal(t, ModuleID("module1_0"), sortedModulesZ[1].ID)
assert.Equal(t, 0, sortedModulesZ[1].Priority)
}
4 changes: 3 additions & 1 deletion router/core/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,9 @@ func (r *Router) listenAndServe(cfg *nodev1.RouterConfig) error {
}

func (r *Router) initModules(ctx context.Context) error {
for _, moduleInfo := range modules {
var moduleList = sortModules(modules)

for _, moduleInfo := range moduleList {
now := time.Now()

moduleInstance := moduleInfo.New()
Expand Down
Loading