5 Commits

Author SHA1 Message Date
7d0620fe3e Fix system config file path 2025-03-09 01:55:11 -05:00
3115c5feef Actors are formatted better when logged 2025-03-09 01:54:53 -05:00
10ca4f4671 Add "named" actor interface 2025-02-05 16:49:27 -05:00
e0c8825949 Clarify documentation for Actor 2025-01-31 17:26:45 -05:00
b12ffdb0a0 Say *why* an actor failed 2025-01-30 21:12:55 -05:00
4 changed files with 34 additions and 10 deletions

View File

@@ -3,20 +3,40 @@ package camfish
import "context" import "context"
// Actor is a participant in the environment. All public methods on an actor // Actor is a participant in the environment. All public methods on an actor
// must be safe for concurrent use by multiple goroutines. Additionally, any // should be safe for concurrent use by multiple goroutines except for AddFlags,
// type which explicitly implements Actor should: // Init, Configure, and ProcessConfig. Additionally, any type which explicitly
// implements Actor should:
//
// - Treat all public fields, values, indices, etc. as immutable // - Treat all public fields, values, indices, etc. as immutable
// - Satisfy Actor as a pointer, not a value // - Satisfy Actor as a pointer, not a value
// - Not have a constructor // - Not have a constructor
//
// The CAMFISH environment will use interfaces in this package to probe actors
// for methods. If an actor is supposed to fulfill one of these interfaces, this
// should be enforced at compile-time by assigning the actor to an anonymous
// global variable of that interface type. For instance, this line will ensure
// that SomeActor fulfills [Resettable]:
//
// var _ camfish.Resettable = new(SomeActor)
type Actor interface { type Actor interface {
// Type returns the type name of the actor. The value returned from this // Type returns the "type name" of the actor. The value returned from
// is used to locate actors capable of performing a specific task, so it // this is used to locate actors capable of performing a specific task,
// absolutely must return the same string every time. Actors implemented // so it absolutely must return the same string every time. It is
// in packages besides this one (i.e. not camfish) must not return the // usually best to have this be unique to each actor. Actors implemented
// string "cron". // in packages other than this one
// (git.tebibyte.media/sashakoshka/camfish) must not return the string
// "cron".
Type() string Type() string
} }
// Named is any object with a name.
type Named() string {
// Name returns the name. This doesn't need to be the same as Type. It
// must return the same string every time. It is used to differentiate
// actors of the same type in logs.
Name() string
}
// FlagAdder is any object that can add [Flag]s to a [FlagSet]. Actors which // FlagAdder is any object that can add [Flag]s to a [FlagSet]. Actors which
// implement this interface will be called upon to add flags during and only // implement this interface will be called upon to add flags during and only
// during the flag parsing phase. // during the flag parsing phase.

View File

@@ -298,7 +298,7 @@ func (this *environment) runRunnable(ctx context.Context, actor Runnable) (stopE
return return
} else { } else {
// failure // failure
log.Printf("XXX [%s] failed", typ) log.Printf("XXX [%s] failed: %v", typ, err)
} }
// restart logic // restart logic

2
ini.go
View File

@@ -162,7 +162,7 @@ func configFiles(program string) ([]string, error) {
userConfig, err := os.UserConfigDir() userConfig, err := os.UserConfigDir()
if err != nil { return nil, err } if err != nil { return nil, err }
return []string { return []string {
filepath.Join("/etc", program), filepath.Join("/etc", program, program + ".conf"),
filepath.Join(userConfig, program), filepath.Join(userConfig, program),
}, nil }, nil
} }

View File

@@ -77,7 +77,11 @@ func logActors (actors iter.Seq[Actor]) {
} }
types := make(map[string] int) types := make(map[string] int)
for actor := range actors { for actor := range actors {
types[actor.Type()] += 1 typ := actor.Type()
if named, ok := actor.(Named); ok {
typ = fmt.Sprintf("%s/%s", typ, named.Name())
}
types[typ] += 1
} }
for typ, count := range types { for typ, count := range types {
if count > 1 { if count > 1 {