44 "context"
55 "embed"
66 "fmt"
7+ "io"
78 "net/http"
89 "strconv"
910
@@ -37,6 +38,7 @@ const (
3738 DefaultHealthCheckStartupPath = "/healthz"
3839 DefaultHealthCheckLivenessPath = "/livez"
3940 DefaultHealthCheckReadinessPath = "/readyz"
41+ DefaultTasksPath = "/tasks"
4042 DefaultDebugConfigPath = "/debug/config"
4143 DefaultDebugPProfPath = "/debug/pprof"
4244 DefaultDebugBuildPath = "/debug/build"
@@ -63,6 +65,7 @@ var FxCoreModule = fx.Module(
6365 fxhealthcheck .FxHealthcheckModule ,
6466 fx .Provide (
6567 NewFxModuleInfoRegistry ,
68+ NewTaskRegistry ,
6669 NewFxCore ,
6770 fx .Annotate (
6871 NewFxCoreModuleInfo ,
@@ -92,7 +95,8 @@ type FxCoreParam struct {
9295 Checker * healthcheck.Checker
9396 Config * config.Config
9497 Logger * log.Logger
95- Registry * FxModuleInfoRegistry
98+ InfoRegistry * FxModuleInfoRegistry
99+ TaskRegistry * TaskRegistry
96100 MetricsRegistry * prometheus.Registry
97101}
98102
@@ -232,7 +236,7 @@ func withHandlers(coreServer *echo.Echo, p FxCoreParam) (*echo.Echo, error) {
232236 dashboardEnabled := p .Config .GetBool ("modules.core.server.dashboard.enabled" )
233237
234238 // dashboard overview
235- overviewInfo , err := p .Registry .Find (ModuleName )
239+ overviewInfo , err := p .InfoRegistry .Find (ModuleName )
236240 if err != nil {
237241 return nil , err
238242 }
@@ -248,6 +252,7 @@ func withHandlers(coreServer *echo.Echo, p FxCoreParam) (*echo.Echo, error) {
248252 overviewTraceProcessorExpose := p .Config .GetBool ("modules.core.server.dashboard.overview.trace_processor" )
249253
250254 // template expositions
255+ tasksExpose := p .Config .GetBool ("modules.core.server.tasks.expose" )
251256 metricsExpose := p .Config .GetBool ("modules.core.server.metrics.expose" )
252257 startupExpose := p .Config .GetBool ("modules.core.server.healthcheck.startup.expose" )
253258 livenessExpose := p .Config .GetBool ("modules.core.server.healthcheck.liveness.expose" )
@@ -260,6 +265,7 @@ func withHandlers(coreServer *echo.Echo, p FxCoreParam) (*echo.Echo, error) {
260265 modulesExpose := p .Config .GetBool ("modules.core.server.debug.modules.expose" )
261266
262267 // template paths
268+ tasksPath := p .Config .GetString ("modules.core.server.tasks.path" )
263269 metricsPath := p .Config .GetString ("modules.core.server.metrics.path" )
264270 startupPath := p .Config .GetString ("modules.core.server.healthcheck.startup.path" )
265271 livenessPath := p .Config .GetString ("modules.core.server.healthcheck.liveness.path" )
@@ -271,6 +277,48 @@ func withHandlers(coreServer *echo.Echo, p FxCoreParam) (*echo.Echo, error) {
271277 buildPath := p .Config .GetString ("modules.core.server.debug.build.path" )
272278 modulesPath := p .Config .GetString ("modules.core.server.debug.modules.path" )
273279
280+ // tasks
281+ if tasksExpose {
282+ if tasksPath == "" {
283+ tasksPath = DefaultTasksPath
284+ }
285+
286+ coreServer .POST (fmt .Sprintf ("%s/:name" , tasksPath ), func (c echo.Context ) error {
287+ ctx := c .Request ().Context ()
288+
289+ logger := log .CtxLogger (ctx )
290+
291+ name := c .Param ("name" )
292+
293+ input , err := io .ReadAll (c .Request ().Body )
294+ if err != nil {
295+ logger .Error ().Err (err ).Str ("task" , name ).Msg ("request body read error" )
296+
297+ return echo .NewHTTPError (http .StatusInternalServerError , fmt .Sprintf ("cannot read request body: %v" , err .Error ()))
298+ }
299+
300+ err = c .Request ().Body .Close ()
301+ if err != nil {
302+ logger .Error ().Err (err ).Str ("task" , name ).Msg ("request body close error" )
303+
304+ return echo .NewHTTPError (http .StatusInternalServerError , fmt .Sprintf ("cannot close request body: %v" , err .Error ()))
305+ }
306+
307+ res := p .TaskRegistry .Run (ctx , name , input )
308+ if ! res .Success {
309+ logger .Error ().Err (err ).Str ("task" , name ).Msg ("task execution error" )
310+
311+ return c .JSON (http .StatusInternalServerError , res )
312+ }
313+
314+ logger .Info ().Str ("task" , name ).Msg ("task execution success" )
315+
316+ return c .JSON (http .StatusOK , res )
317+ })
318+
319+ coreServer .Logger .Debug ("registered tasks handler" )
320+ }
321+
274322 // metrics
275323 if metricsExpose {
276324 if metricsPath == "" {
@@ -393,14 +441,14 @@ func withHandlers(coreServer *echo.Echo, p FxCoreParam) (*echo.Echo, error) {
393441 coreServer .Logger .Debug ("registered debug build handler" )
394442 }
395443
396- // debug modules
444+ // modules
397445 if modulesExpose || appDebug {
398446 if modulesPath == "" {
399447 modulesPath = DefaultDebugModulesPath
400448 }
401449
402450 coreServer .GET (fmt .Sprintf ("%s/:name" , modulesPath ), func (c echo.Context ) error {
403- info , err := p .Registry .Find (c .Param ("name" ))
451+ info , err := p .InfoRegistry .Find (c .Param ("name" ))
404452 if err != nil {
405453 return echo .NewHTTPError (http .StatusNotFound , err .Error ())
406454 }
@@ -466,6 +514,9 @@ func withHandlers(coreServer *echo.Echo, p FxCoreParam) (*echo.Echo, error) {
466514 "overviewLogOutputExpose" : overviewLogOutputExpose ,
467515 "overviewTraceSamplerExpose" : overviewTraceSamplerExpose ,
468516 "overviewTraceProcessorExpose" : overviewTraceProcessorExpose ,
517+ "tasksExpose" : tasksExpose ,
518+ "tasksPath" : tasksPath ,
519+ "tasksNames" : p .TaskRegistry .Names (),
469520 "metricsExpose" : metricsExpose ,
470521 "metricsPath" : metricsPath ,
471522 "startupExpose" : startupExpose ,
@@ -486,7 +537,7 @@ func withHandlers(coreServer *echo.Echo, p FxCoreParam) (*echo.Echo, error) {
486537 "buildPath" : buildPath ,
487538 "modulesExpose" : modulesExpose || appDebug ,
488539 "modulesPath" : modulesPath ,
489- "modulesNames" : p .Registry .Names (),
540+ "modulesNames" : p .InfoRegistry .Names (),
490541 "theme" : theme ,
491542 })
492543 })
0 commit comments