Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
4e3358d
feat(fxcore): Added core tasks system
ekkinox Mar 11, 2025
a675424
feat(fxcore): Added core tasks system
ekkinox Mar 11, 2025
1fe4277
feat(fxcore): Added core tasks system
ekkinox Mar 11, 2025
72be8c7
feat(fxcore): Added core tasks system
ekkinox Mar 11, 2025
3a96d04
feat(fxcore): Added core tasks system
ekkinox Mar 12, 2025
8dcdcfe
feat(fxcore): Added core tasks system
ekkinox Mar 12, 2025
002160a
feat(fxcore): Added core tasks system
ekkinox Mar 12, 2025
d38cc3f
feat(fxcore): Added core tasks system
ekkinox Mar 12, 2025
07de439
feat(fxcore): Added core tasks system
ekkinox Mar 12, 2025
8b8fafe
feat(fxcore): Added core tasks system
ekkinox Mar 12, 2025
d8dea6a
feat(fxcore): Added core tasks system
ekkinox Mar 12, 2025
d9d950e
feat(fxcore): Added core tasks system
ekkinox Mar 12, 2025
2edb2f0
feat(fxcore): Added core tasks system
ekkinox Mar 13, 2025
491f0b2
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
993c341
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
c3bbe0e
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
6bc2e44
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
ccd737d
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
e31b088
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
a77bf81
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
d11b6ce
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
1fc0ee7
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
f8a0bdc
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
91ca4bd
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
9bcabce
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
6872f1d
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
b82774c
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
ffea1de
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
a0284cd
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
fff3faf
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
2534625
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
a5bd53e
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
b24de88
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
142c292
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
b6516b0
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
e8ff7fb
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
90bd755
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
135eb76
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
5a54181
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
191bd0e
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
c0c4c17
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
b44b3a9
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
f79d0fc
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
529ba8e
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
99371ff
doc(fxhttpclient): Updated documentation
ekkinox Mar 13, 2025
023d99b
feat(fxcore): Added core tasks system
ekkinox Mar 13, 2025
6f5b899
feat(fxcore): Added core tasks system
ekkinox Mar 13, 2025
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
3 changes: 3 additions & 0 deletions fxcore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ modules:
liveness:
expose: true # to expose health check liveness route, disabled by default
path: /livez # health check liveness route path (default /livez)
tasks:
expose: true # to expose tasks route, disabled by default
path: /tasks/:name # tasks route path (default /tasks/:name)
debug:
config:
expose: true # to expose debug config route
Expand Down
2 changes: 1 addition & 1 deletion fxcore/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ require (
github.com/ankorstore/yokai/healthcheck v1.1.0
github.com/ankorstore/yokai/httpserver v1.6.0
github.com/ankorstore/yokai/log v1.2.0
github.com/ankorstore/yokai/trace v1.3.0
github.com/ankorstore/yokai/trace v1.4.0
github.com/arl/statsviz v0.6.0
github.com/labstack/echo/v4 v4.13.3
github.com/labstack/gommon v0.4.2
Expand Down
2 changes: 2 additions & 0 deletions fxcore/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ github.com/ankorstore/yokai/log v1.2.0 h1:jiuDiC0dtqIGIOsFQslUHYoFJ1qjI+rOMa6dI1
github.com/ankorstore/yokai/log v1.2.0/go.mod h1:MVvUcms1AYGo0BT6l88B9KJdvtK6/qGKdgyKVXfbmyc=
github.com/ankorstore/yokai/trace v1.3.0 h1:0ji32oymIcxTmH5h6GRWLo5ypwBbWrZkXRf9rWF9070=
github.com/ankorstore/yokai/trace v1.3.0/go.mod h1:m7EL2MRBilgCtrly5gA4F0jkGSXR2EbG6LsotbTJ4nA=
github.com/ankorstore/yokai/trace v1.4.0 h1:AdEQs/4TEuqOJ9p/EfsQmrtmkSG3pcmE7r/l+FQFxY8=
github.com/ankorstore/yokai/trace v1.4.0/go.mod h1:m7EL2MRBilgCtrly5gA4F0jkGSXR2EbG6LsotbTJ4nA=
github.com/arl/statsviz v0.6.0 h1:jbW1QJkEYQkufd//4NDYRSNBpwJNrdzPahF7ZmoGdyE=
github.com/arl/statsviz v0.6.0/go.mod h1:0toboo+YGSUXDaS4g1D5TVS4dXs7S7YYT5J/qnW2h8s=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
Expand Down
57 changes: 57 additions & 0 deletions fxcore/info.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package fxcore

import (
"fmt"
"sort"

"github.com/ankorstore/yokai/config"
"github.com/ankorstore/yokai/log"
"github.com/ankorstore/yokai/trace"
Expand Down Expand Up @@ -129,3 +132,57 @@ func (i *FxCoreModuleInfo) Data() map[string]interface{} {
"extra": i.ExtraInfos,
}
}

// FxModuleInfoRegistry is the registry collecting info about registered modules.
type FxModuleInfoRegistry struct {
infos map[string]FxModuleInfo
}

// FxModuleInfoRegistryParam allows injection of the required dependencies in [NewFxModuleInfoRegistry].
type FxModuleInfoRegistryParam struct {
fx.In
Infos []any `group:"core-module-infos"`
}

// NewFxModuleInfoRegistry returns a new [FxModuleInfoRegistry].
func NewFxModuleInfoRegistry(p FxModuleInfoRegistryParam) *FxModuleInfoRegistry {
infos := make(map[string]FxModuleInfo)

for _, info := range p.Infos {
if castInfo, ok := info.(FxModuleInfo); ok {
infos[castInfo.Name()] = castInfo
}
}

return &FxModuleInfoRegistry{
infos: infos,
}
}

func (r *FxModuleInfoRegistry) Names() []string {
names := make([]string, len(r.infos))

i := 0
for name := range r.infos {
names[i] = name
i++
}

sort.Strings(names)

return names
}

// All returns a map of all registered [FxModuleInfo].
func (r *FxModuleInfoRegistry) All() map[string]FxModuleInfo {
return r.infos
}

// Find returns a [FxModuleInfo] by name.
func (r *FxModuleInfoRegistry) Find(name string) (FxModuleInfo, error) {
if info, ok := r.infos[name]; ok {
return info, nil
}

return nil, fmt.Errorf("fx module info with name %s was not found", name)
}
79 changes: 78 additions & 1 deletion fxcore/info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,17 @@ import (
"github.com/stretchr/testify/assert"
)

func TestNewFxCoreModuleInfo(t *testing.T) {
type testModuleInfo struct{}

func (i *testModuleInfo) Name() string {
return "test"
}

func (i *testModuleInfo) Data() map[string]interface{} {
return map[string]interface{}{}
}

func TestFxCoreModuleInfo(t *testing.T) {
t.Setenv("APP_ENV", "test")

cfg, err := config.NewDefaultConfigFactory().Create(
Expand Down Expand Up @@ -54,3 +64,70 @@ func TestNewFxCoreModuleInfo(t *testing.T) {
info.Data(),
)
}

func TestFxModuleInfoRegistry(t *testing.T) {
t.Parallel()

createRegistry := func(tb testing.TB) *fxcore.FxModuleInfoRegistry {
tb.Helper()

cfg, err := config.NewDefaultConfigFactory().Create(
config.WithFilePaths("./testdata/config"),
)
assert.NoError(tb, err)

return fxcore.NewFxModuleInfoRegistry(fxcore.FxModuleInfoRegistryParam{
Infos: []interface{}{
&testModuleInfo{},
fxcore.NewFxCoreModuleInfo(fxcore.FxCoreModuleInfoParam{
Config: cfg,
ExtraInfos: []fxcore.FxExtraInfo{},
}),
"invalid",
},
})
}

t.Run("test type", func(t *testing.T) {
t.Parallel()

registry := createRegistry(t)

assert.IsType(t, &fxcore.FxModuleInfoRegistry{}, registry)
})

t.Run("test all", func(t *testing.T) {
t.Parallel()

registry := createRegistry(t)

assert.Len(t, registry.All(), 2)
})

t.Run("test names", func(t *testing.T) {
t.Parallel()

registry := createRegistry(t)

assert.Equal(t, []string{fxcore.ModuleName, "test"}, registry.Names())
})

t.Run("test find", func(t *testing.T) {
t.Parallel()

registry := createRegistry(t)

testInfo, err := registry.Find("test")
assert.NoError(t, err)
assert.Equal(t, "test", testInfo.Name())

coreInfo, err := registry.Find(fxcore.ModuleName)
assert.NoError(t, err)
assert.Equal(t, fxcore.ModuleName, coreInfo.Name())

invalidInfo, err := registry.Find("invalid")
assert.Error(t, err)
assert.Equal(t, "fx module info with name invalid was not found", err.Error())
assert.Nil(t, invalidInfo)
})
}
61 changes: 56 additions & 5 deletions fxcore/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"context"
"embed"
"fmt"
"io"
"net/http"
"strconv"

Expand Down Expand Up @@ -37,6 +38,7 @@
DefaultHealthCheckStartupPath = "/healthz"
DefaultHealthCheckLivenessPath = "/livez"
DefaultHealthCheckReadinessPath = "/readyz"
DefaultTasksPath = "/tasks"
DefaultDebugConfigPath = "/debug/config"
DefaultDebugPProfPath = "/debug/pprof"
DefaultDebugBuildPath = "/debug/build"
Expand All @@ -63,6 +65,7 @@
fxhealthcheck.FxHealthcheckModule,
fx.Provide(
NewFxModuleInfoRegistry,
NewTaskRegistry,
NewFxCore,
fx.Annotate(
NewFxCoreModuleInfo,
Expand Down Expand Up @@ -92,7 +95,8 @@
Checker *healthcheck.Checker
Config *config.Config
Logger *log.Logger
Registry *FxModuleInfoRegistry
InfoRegistry *FxModuleInfoRegistry
TaskRegistry *TaskRegistry
MetricsRegistry *prometheus.Registry
}

Expand Down Expand Up @@ -232,7 +236,7 @@
dashboardEnabled := p.Config.GetBool("modules.core.server.dashboard.enabled")

// dashboard overview
overviewInfo, err := p.Registry.Find(ModuleName)
overviewInfo, err := p.InfoRegistry.Find(ModuleName)
if err != nil {
return nil, err
}
Expand All @@ -248,6 +252,7 @@
overviewTraceProcessorExpose := p.Config.GetBool("modules.core.server.dashboard.overview.trace_processor")

// template expositions
tasksExpose := p.Config.GetBool("modules.core.server.tasks.expose")
metricsExpose := p.Config.GetBool("modules.core.server.metrics.expose")
startupExpose := p.Config.GetBool("modules.core.server.healthcheck.startup.expose")
livenessExpose := p.Config.GetBool("modules.core.server.healthcheck.liveness.expose")
Expand All @@ -260,6 +265,7 @@
modulesExpose := p.Config.GetBool("modules.core.server.debug.modules.expose")

// template paths
tasksPath := p.Config.GetString("modules.core.server.tasks.path")
metricsPath := p.Config.GetString("modules.core.server.metrics.path")
startupPath := p.Config.GetString("modules.core.server.healthcheck.startup.path")
livenessPath := p.Config.GetString("modules.core.server.healthcheck.liveness.path")
Expand All @@ -271,6 +277,48 @@
buildPath := p.Config.GetString("modules.core.server.debug.build.path")
modulesPath := p.Config.GetString("modules.core.server.debug.modules.path")

// tasks
if tasksExpose {
if tasksPath == "" {
tasksPath = DefaultTasksPath
}

coreServer.POST(fmt.Sprintf("%s/:name", tasksPath), func(c echo.Context) error {
ctx := c.Request().Context()

logger := log.CtxLogger(ctx)

name := c.Param("name")

input, err := io.ReadAll(c.Request().Body)
if err != nil {
logger.Error().Err(err).Str("task", name).Msg("request body read error")

return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("cannot read request body: %v", err.Error()))
}

Check warning on line 298 in fxcore/module.go

View check run for this annotation

Codecov / codecov/patch

fxcore/module.go#L295-L298

Added lines #L295 - L298 were not covered by tests

err = c.Request().Body.Close()
if err != nil {
logger.Error().Err(err).Str("task", name).Msg("request body close error")

return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("cannot close request body: %v", err.Error()))
}

Check warning on line 305 in fxcore/module.go

View check run for this annotation

Codecov / codecov/patch

fxcore/module.go#L302-L305

Added lines #L302 - L305 were not covered by tests

res := p.TaskRegistry.Run(ctx, name, input)
if !res.Success {
logger.Error().Err(err).Str("task", name).Msg("task execution error")

return c.JSON(http.StatusInternalServerError, res)
}

logger.Info().Str("task", name).Msg("task execution success")

return c.JSON(http.StatusOK, res)
})

coreServer.Logger.Debug("registered tasks handler")
}

// metrics
if metricsExpose {
if metricsPath == "" {
Expand Down Expand Up @@ -393,14 +441,14 @@
coreServer.Logger.Debug("registered debug build handler")
}

// debug modules
// modules
if modulesExpose || appDebug {
if modulesPath == "" {
modulesPath = DefaultDebugModulesPath
}

coreServer.GET(fmt.Sprintf("%s/:name", modulesPath), func(c echo.Context) error {
info, err := p.Registry.Find(c.Param("name"))
info, err := p.InfoRegistry.Find(c.Param("name"))
if err != nil {
return echo.NewHTTPError(http.StatusNotFound, err.Error())
}
Expand Down Expand Up @@ -466,6 +514,9 @@
"overviewLogOutputExpose": overviewLogOutputExpose,
"overviewTraceSamplerExpose": overviewTraceSamplerExpose,
"overviewTraceProcessorExpose": overviewTraceProcessorExpose,
"tasksExpose": tasksExpose,
"tasksPath": tasksPath,
"tasksNames": p.TaskRegistry.Names(),
"metricsExpose": metricsExpose,
"metricsPath": metricsPath,
"startupExpose": startupExpose,
Expand All @@ -486,7 +537,7 @@
"buildPath": buildPath,
"modulesExpose": modulesExpose || appDebug,
"modulesPath": modulesPath,
"modulesNames": p.Registry.Names(),
"modulesNames": p.InfoRegistry.Names(),
"theme": theme,
})
})
Expand Down
Loading
Loading