___________
\__ ___/____ ____
| | \__ \ / _ \
| | / __ \( <_> )
|____| (____ /\____/
\/The Tao produced One; One produced Two; Two produced Three; Three produced All things.
Tao is a lightweight, modular Go application framework designed for building scalable and maintainable applications. It provides a pipeline-based task scheduling system, factory-pattern component management, configuration management, and graceful shutdown capabilities.
- 🏭 Generic Factory Pattern - Type-safe component factories with multi-instance support via
BaseFactory[T] - ⚙️ Flexible Configuration - Support for YAML/JSON config files, auto-detecting single/multi-instance modes
- 📝 Structured Logging - Built-in multi-level logging system with customizable outputs
- 🔄 Graceful Shutdown - Proper resource cleanup on application termination
- 🧩 Modular Design - Easy to extend with custom components using
Register[T, C]() - 🎯 Context Aware - Full support for Go's context package for cancellation and timeouts
go get github.com/taouniverse/taoCreate conf/config.yaml:
tao:
log:
level: debug
type: console
flag: std|short
call_depth: 3
disable: false
banner:
hide: falsepackage main
import (
"context"
"github.com/taouniverse/tao"
)
// InstanceConfig stores per-instance fields
type MyInstanceConfig struct {
Message string `json:"message"`
}
// Config implements tao.MultiConfig for multi-instance support
type MyConfig struct {
tao.BaseMultiConfig[MyInstanceConfig]
}
func (c *MyConfig) Name() string { return "myapp" }
func (c *MyConfig) ValidSelf() {}
func (c *MyConfig) ToTask() tao.Task { return nil }
func (c *MyConfig) RunAfter() []string { return nil }
var Factory *tao.BaseFactory[string]
func init() {
var err error
Factory, err = tao.Register("myapp", &MyConfig{}, NewMyApp)
if err != nil {
panic(err)
}
}
func NewMyApp(name string, cfg MyInstanceConfig) (string, func() error, error) {
closer := func() error { return nil }
return cfg.Message, closer, nil
}
func main() {
if err := tao.Run(context.Background(), nil); err != nil {
panic(err)
}
}go run main.goRegister[T any, C any]() is the unified entry point for all components:
// Multi-instance mode (config implements MultiConfig[C])
factory, _ := tao.Register[*gorm.DB, InstanceConfig]("mysql", &Config{}, NewMySQL)
// Single-instance mode (config does NOT implement MultiConfig)
factory, _ := tao.Register[*gin.Engine, Config]("gin", &Config{}, NewGin)
// Pure config registration (constructor = nil)
_, _ := tao.Register[struct{}, struct{}]("mytask", &TaskConfig{}, nil)factory := tao.NewBaseFactory[*gorm.DB]()
factory.RegisterWithCloser("master", dbMaster, dbMaster.Close)
factory.RegisterWithCloser("replica", dbReplica, dbReplica.Close)
db, _ := factory.Get("master")
names := factory.Names()
count := factory.Count()
factory.CloseAll()type MultiConfig[C any] interface {
tao.Config
GetInstances() map[string]C
SetInstances(instances map[string]C)
GetDefaultInstanceName() string
}Embed BaseMultiConfig[C] to get the implementation for free:
type Config struct {
tao.BaseMultiConfig[InstanceConfig]
RunAfters []string `json:"run_after,omitempty"`
}The basic unit of work in Tao:
task := tao.NewTask("mytask", func(ctx context.Context, param tao.Parameter) (tao.Parameter, error) {
// Your logic here
return param, nil
}, tao.SetClose(func() error {
// Cleanup logic
return nil
}))A Pipeline orchestrates multiple tasks with dependencies:
pipeline := tao.NewPipeline("mypipeline")
pipeline.Register(tao.NewPipeTask(task1))
pipeline.Register(tao.NewPipeTask(task2, "task1")) // task2 depends on task1Implement the Config interface for your module:
type Config interface {
Name() string // Config identifier
ValidSelf() // Set default values
ToTask() Task // Convert to executable task
RunAfter() []string // Dependency task names
}For multi-instance components, implement MultiConfig[C] instead.
Tao provides multiple logging levels:
tao.Debug("debug message")
tao.Info("info message")
tao.Warn("warning message")
tao.Error("error message")tao/
├── tao.go # Core Universe, Run(), Register[T,C]()
├── factory.go # Factory[T] interface + BaseFactory[T]
├── config.go # Config/MultiConfig interfaces + parseMultiConfig
├── pipeline.go # Pipeline implementation for task orchestration
├── task.go # Task interface and implementation
├── init.go # Initialization and config loading
├── log.go # Logging system
├── param.go # Parameter passing between tasks
├── error.go # Error handling utilities
├── factory_test.go # Factory & BaseMultiConfig tests
└── config_test.go # Config & parseMultiConfig tests
The core library has comprehensive test coverage:
| Test File | Coverage |
|---|---|
factory_test.go |
BaseFactory[T] — CRUD, close, concurrent access, benchmarks (14 tests) |
config_test.go |
BaseMultiConfig[C], parseMultiConfig — single/multi-instance parsing, nested structs, edge cases (16 tests) |
init_test.go |
Pre-init registration, config path handling |
tao_test.go |
Register, Run lifecycle |
log_test.go |
LogLevel, LogType, LogFlag marshaling |
pipeline_test.go |
Pipeline orchestration, dependencies, errors |
task_test.go |
Task lifecycle, result propagation |
# All tests
cd tao && go test -v ./...
# Specific category
cd tao && go test -v -run "TestFactory" ./...
cd tao && go test -v -run "TestParseMultiConfig" ./...
# With coverage
cd tao && go test -race -coverprofile=coverage.out ./...mysql:
default_instance: master
master:
host: 10.0.0.1
port: 3306
user: app
password: secret
db: production
replica:
host: 10.0.0.2
port: 3306
user: readonly
db: productionmasterDB, _ := mysql.GetDB("master")
replicaDB, _ := mysql.GetDB("replica")writer := os.Stdout
logger := &myCustomLogger{}
tao.SetWriter("myapp", writer)
tao.SetLogger("myapp", logger)For quick testing without configuration files:
func init() {
tao.DevelopMode() // Uses default configurations
}configData := []byte(`
tao:
log:
level: info
type: console
`)
tao.SetAllConfigBytes(configData, tao.Yaml)| Component | Description | Factory Type |
|---|---|---|
| tao-mysql | MySQL via GORM | *BaseFactory[*gorm.DB] |
| tao-postgres | PostgreSQL via GORM | *BaseFactory[*gorm.DB] |
| tao-sqlite | SQLite via GORM (pure Go) | *BaseFactory[*gorm.DB] |
| tao-redis | Redis via go-redis | *BaseFactory[redis.UniversalClient] |
| tao-mongodb | MongoDB via mongo-driver | *BaseFactory[*mongo.Client] |
| tao-gin | Gin HTTP framework | *BaseFactory[*gin.Engine] |
| tao-websocket | WebSocket support | *BaseFactory[ws.Upgrader] |
| tao-zap | Zap structured logging | *BaseFactory[*zap.SugaredLogger] |
| tao-hello | Example component template | *BaseFactory[struct{}] |
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.