Codex-authored docs covering primitives, commands, messaging, lifecycle, subsystems, and getting started — all using the current DTO/Options/Result API with concrete usage examples. Co-Authored-By: Virgil <virgil@lethean.io>
3.7 KiB
| title | description |
|---|---|
| Messaging | ACTION, QUERY, QUERYALL, PERFORM, and async task flow. |
Messaging
CoreGO uses one message bus for broadcasts, lookups, and work dispatch.
Message Types
type Message any
type Query any
type Task any
Your own structs define the protocol.
type repositoryIndexed struct {
Name string
}
type repositoryCountQuery struct{}
type syncRepositoryTask struct {
Name string
}
ACTION
ACTION is a broadcast.
c.RegisterAction(func(_ *core.Core, msg core.Message) core.Result {
switch m := msg.(type) {
case repositoryIndexed:
core.Info("repository indexed", "name", m.Name)
return core.Result{OK: true}
}
return core.Result{OK: true}
})
r := c.ACTION(repositoryIndexed{Name: "core-go"})
Behavior
- all registered action handlers are called in their current registration order
- if a handler returns
OK:false, dispatch stops and thatResultis returned - if no handler fails,
ACTIONreturnsResult{OK:true}
QUERY
QUERY is first-match request-response.
c.RegisterQuery(func(_ *core.Core, q core.Query) core.Result {
switch q.(type) {
case repositoryCountQuery:
return core.Result{Value: 42, OK: true}
}
return core.Result{}
})
r := c.QUERY(repositoryCountQuery{})
Behavior
- handlers run until one returns
OK:true - the first successful result wins
- if nothing handles the query, CoreGO returns an empty
Result
QUERYALL
QUERYALL collects every successful non-nil response.
r := c.QUERYALL(repositoryCountQuery{})
results := r.Value.([]any)
Behavior
- every query handler is called
- only
OK:trueresults with non-nilValueare collected - the call itself returns
OK:trueeven when the result list is empty
PERFORM
PERFORM dispatches a task to the first handler that accepts it.
c.RegisterTask(func(_ *core.Core, t core.Task) core.Result {
switch task := t.(type) {
case syncRepositoryTask:
return core.Result{Value: "synced " + task.Name, OK: true}
}
return core.Result{}
})
r := c.PERFORM(syncRepositoryTask{Name: "core-go"})
Behavior
- handlers run until one returns
OK:true - the first successful result wins
- if nothing handles the task, CoreGO returns an empty
Result
PerformAsync
PerformAsync runs a task in a background goroutine and returns a generated task identifier.
r := c.PerformAsync(syncRepositoryTask{Name: "core-go"})
taskID := r.Value.(string)
Generated Events
Async execution emits three action messages:
| Message | When |
|---|---|
ActionTaskStarted |
just before background execution begins |
ActionTaskProgress |
whenever Progress is called |
ActionTaskCompleted |
after the task finishes or panics |
Example listener:
c.RegisterAction(func(_ *core.Core, msg core.Message) core.Result {
switch m := msg.(type) {
case core.ActionTaskCompleted:
core.Info("task completed", "task", m.TaskIdentifier, "err", m.Error)
}
return core.Result{OK: true}
})
Progress Updates
c.Progress(taskID, 0.5, "indexing commits", syncRepositoryTask{Name: "core-go"})
That broadcasts ActionTaskProgress.
TaskWithIdentifier
Tasks that implement TaskWithIdentifier receive the generated ID before dispatch.
type trackedTask struct {
ID string
Name string
}
func (t *trackedTask) SetTaskIdentifier(id string) { t.ID = id }
func (t *trackedTask) GetTaskIdentifier() string { return t.ID }
Shutdown Interaction
When shutdown has started, PerformAsync returns an empty Result instead of scheduling more work.
This is why ServiceShutdown can safely drain the outstanding background tasks before stopping services.