package biz import ( "context" "encoding/json" "sort" "sync" ) // TaskMethodFunc is the execution contract for a registered in-process task. // Implementations are responsible for decoding params and honoring ctx cancellation. type TaskMethodFunc func(ctx context.Context, params json.RawMessage) error type TaskMethod struct { Name string Description string } type taskMethodEntry struct { meta TaskMethod fn TaskMethodFunc } var taskMethodRegistry = struct { sync.RWMutex methods map[string]taskMethodEntry }{methods: make(map[string]taskMethodEntry)} // RegisterTaskMethod registers an in-process task. Re-registering the same name // replaces the previous implementation so startup registration remains idempotent. func RegisterTaskMethod(name, description string, fn TaskMethodFunc) { taskMethodRegistry.Lock() defer taskMethodRegistry.Unlock() taskMethodRegistry.methods[name] = taskMethodEntry{ meta: TaskMethod{Name: name, Description: description}, fn: fn, } } // TaskMethodByName returns the registered function for name. func TaskMethodByName(name string) (TaskMethodFunc, bool) { taskMethodRegistry.RLock() defer taskMethodRegistry.RUnlock() method, ok := taskMethodRegistry.methods[name] if !ok { return nil, false } return method.fn, true } // RegisteredTaskMethods returns task metadata in a stable name order. func RegisteredTaskMethods() []TaskMethod { taskMethodRegistry.RLock() defer taskMethodRegistry.RUnlock() methods := make([]TaskMethod, 0, len(taskMethodRegistry.methods)) for _, method := range taskMethodRegistry.methods { methods = append(methods, method.meta) } sort.Slice(methods, func(i, j int) bool { return methods[i].Name < methods[j].Name }) return methods } func registeredTaskMethod(name string) bool { _, ok := TaskMethodByName(name) return ok }