tao

package module
v0.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 12, 2026 License: Apache-2.0 Imports: 17 Imported by: 14

README

tao

MainTest Go Report Card codecov GoDoc GitHub release (latest by date)

___________              
\__    ___/____    ____  
  |    |  \__  \  /  _ \ 
  |    |   / __ \(  <_> )
  |____|  (____  /\____/ 
               \/

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.

Features

  • 🏭 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

Installation

go get github.com/taouniverse/tao

Quick Start

1. Create a Configuration File

Create conf/config.yaml:

tao:
  log:
    level: debug
    type: console
    flag: std|short
    call_depth: 3
    disable: false
  banner:
    hide: false
2. Define Your Component (with Factory Pattern)
package 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)
    }
}
3. Run Your Application
go run main.go

Core Concepts

Register — Generic Component Registration

Register[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)
BaseFactory[T] — Type-Safe Component Factory
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()
MultiConfig[C] — Multi-Instance Configuration Interface
type MultiConfig[C any] interface {
    tao.Config
    GetInstances() []Instance[C]
    SetInstances(instances []Instance[C])
    GetDefaultInstanceName() string
}

Embed BaseMultiConfig[C] to get the implementation for free:

type Config struct {
    tao.BaseMultiConfig[InstanceConfig]
    RunAfters []string `json:"run_after,omitempty"`
}

Instances are stored as an ordered slice to preserve creation order:

type Instance[C any] struct {
    Name string
    Cfg  C
}

Use GetInstanceByName(name string) (C, bool) to look up a specific instance by name.

Task

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
}))
Pipeline

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 task1
Configuration

Implement 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.

Logging

Tao provides multiple logging levels:

tao.Debug("debug message")
tao.Info("info message")
tao.Warn("warning message")
tao.Error("error message")

Project Structure

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

Unit 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
Running Tests
# 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 ./...

Advanced Usage

Multi-Instance Database Pattern
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: production
masterDB, _ := mysql.GetDB("master")
replicaDB, _ := mysql.GetDB("replica")
Custom Logger
writer := os.Stdout
logger := &myCustomLogger{}
tao.SetWriter("myapp", writer)
tao.SetLogger("myapp", logger)
Development Mode

For quick testing without configuration files:

func init() {
    tao.DevelopMode() // Uses default configurations
}
Programmatic Configuration
configData := []byte(`
tao:
  log:
    level: info
    type: console
`)
tao.SetAllConfigBytes(configData, tao.Yaml)

Ecosystem Components

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{}]

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

Documentation

Index

Constants

View Source
const (
	Unknown            = "Unknown"
	ParamInvalid       = "ParamInvalid"
	ContextCanceled    = "ContextCanceled"
	DuplicateCall      = "DuplicateCall"
	TaskRunError       = "TaskRunError"
	TaskRunTwice       = "TaskRunTwice"
	TaskCloseTwice     = "TaskCloseTwice"
	TaskClosed         = "TaskClosed"
	TaskRunning        = "TaskRunning"
	ConfigNotFound     = "ConfigNotFound"
	UniverseNotInit    = "UniverseNotInit"
	InstancesNotClosed = "InstancesNotClosed"
)

ErrorCode

View Source
const ConfigKey = "tao"

ConfigKey for this repo

View Source
const DefaultInstanceKey = "default"

DefaultInstanceKey is the default instance name for single-instance configs

Variables

View Source
var Add = tao.Add

Add of tao

View Source
var Done = tao.Done

Done of tao

View Source
var UniverseInitTimeout = time.Minute

UniverseInitTimeout is the timeout for universe initialization. Default is 1 minute. Can be changed before calling tao.Run().

Functions

func Debug

func Debug(v ...interface{})

Debug function wrap of taoLogger

func Debugf

func Debugf(format string, v ...interface{})

Debugf function wrap of taoLogger

func DeleteLogger added in v0.0.3

func DeleteLogger(configKey string) error

DeleteLogger of tao

func DeleteWriter added in v0.0.3

func DeleteWriter(configKey string) error

DeleteWriter of tao

func DevelopMode added in v0.0.4

func DevelopMode() error

DevelopMode called to enable default configs for all

func Error

func Error(v ...interface{})

Error function wrap of taoLogger

func Errorf

func Errorf(format string, v ...interface{})

Errorf function wrap of taoLogger

func Fatal

func Fatal(v ...interface{})

Fatal function wrap of taoLogger

func Fatalf

func Fatalf(format string, v ...interface{})

Fatalf function wrap of taoLogger

func GetWriter added in v0.0.3

func GetWriter(configKey string) io.Writer

GetWriter in tao

func Info

func Info(v ...interface{})

Info function wrap of taoLogger

func Infof

func Infof(format string, v ...interface{})

Infof function wrap of taoLogger

func LoadConfig added in v0.1.5

func LoadConfig(configKey string, config Config) error

LoadConfig by key of config

func Panic

func Panic(v ...interface{})

Panic function wrap of taoLogger

func Panicf

func Panicf(format string, v ...interface{})

Panicf function wrap of taoLogger

func Run

func Run(ctx context.Context, param Parameter) (err error)

Run tao

func SetAllConfigBytes added in v0.1.4

func SetAllConfigBytes(data []byte, configType ConfigType) (err error)

SetAllConfigBytes from config file or code

func SetConfig

func SetConfig(configKey string, config Config) error

SetConfig by key & Config

func SetConfigPath added in v0.0.4

func SetConfigPath(confPath string) error

SetConfigPath in your project's init()

func SetLogger added in v0.0.3

func SetLogger(configKey string, logger Logger) error

SetLogger to tao

func SetWriter added in v0.0.3

func SetWriter(configKey string, w io.Writer) error

SetWriter to tao

func Warn

func Warn(v ...interface{})

Warn function wrap of taoLogger

func Warnf

func Warnf(format string, v ...interface{})

Warnf function wrap of taoLogger

Types

type Banner struct {
	Hide    bool   `json:"hide"`
	Content string `json:"content"`
}

Banner config

type BaseFactory added in v0.2.0

type BaseFactory[T any] struct {
	// contains filtered or unexported fields
}

BaseFactory 工厂基础实现

func NewBaseFactory added in v0.2.0

func NewBaseFactory[T any]() *BaseFactory[T]

NewBaseFactory creates a new BaseFactory instance

func Register added in v0.0.4

func Register[T any, C any](
	configKey string,
	config MultiConfig[C],
	constructor func(name string, cfg C) (T, func() error, error),
) (*BaseFactory[T], error)

Register unit to tao universe.

Generic factory pattern registration with MultiConfig:

  • Parses multi-instance config (single-instance config is auto-wrapped as {default: config})
  • Calls constructor for each instance

func (*BaseFactory[T]) Close added in v0.2.0

func (f *BaseFactory[T]) Close(name string) error

func (*BaseFactory[T]) CloseAll added in v0.2.0

func (f *BaseFactory[T]) CloseAll() error

func (*BaseFactory[T]) Count added in v0.2.0

func (f *BaseFactory[T]) Count() int

func (*BaseFactory[T]) Get added in v0.2.0

func (f *BaseFactory[T]) Get(name string) (T, error)

func (*BaseFactory[T]) Has added in v0.2.0

func (f *BaseFactory[T]) Has(name string) bool

func (*BaseFactory[T]) Names added in v0.2.0

func (f *BaseFactory[T]) Names() []string

func (*BaseFactory[T]) Register added in v0.2.0

func (f *BaseFactory[T]) Register(name string, instance T) error

func (*BaseFactory[T]) RegisterWithCloser added in v0.2.0

func (f *BaseFactory[T]) RegisterWithCloser(name string, instance T, closer func() error) error

type BaseMultiConfig added in v0.2.0

type BaseMultiConfig[C any] struct {
	Instances []Instance[C] `json:"-" yaml:"-"`
	Default   string        `json:"default_instance" yaml:"default_instance"`
}

BaseMultiConfig 多实例配置基础实现

func (*BaseMultiConfig[C]) GetDefaultInstanceName added in v0.2.0

func (b *BaseMultiConfig[C]) GetDefaultInstanceName() string

GetDefaultInstanceName returns the default instance name

func (*BaseMultiConfig[C]) GetInstanceByName added in v0.2.1

func (b *BaseMultiConfig[C]) GetInstanceByName(name string) (C, bool)

GetInstanceByName returns the instance config by name

func (*BaseMultiConfig[C]) GetInstances added in v0.2.0

func (b *BaseMultiConfig[C]) GetInstances() []Instance[C]

GetInstances returns the instances slice

func (*BaseMultiConfig[C]) MarshalJSON added in v0.2.0

func (b *BaseMultiConfig[C]) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler to restore original config file structure. - Single instance (only "default" key): outputs flat config for easy editing - Multi-instance: outputs named instance keys with default_instance field Includes ValidSelf supplemented defaults

func (*BaseMultiConfig[C]) SetDefaultInstanceName added in v0.2.0

func (b *BaseMultiConfig[C]) SetDefaultInstanceName(name string)

SetDefaultInstanceName sets the default instance name

func (*BaseMultiConfig[C]) SetInstances added in v0.2.0

func (b *BaseMultiConfig[C]) SetInstances(instances []Instance[C])

SetInstances sets the instances slice

type Config

type Config interface {
	// Name of Config
	Name() string
	// ValidSelf with some default values
	ValidSelf()
	// ToTask transform itself to Task
	ToTask() Task
	// RunAfter defines pre task names
	RunAfter() []string
}

Config interface

type ConfigType added in v0.0.2

type ConfigType uint8

ConfigType of config file

const (
	// None of config
	None ConfigType = iota
	// Yaml config
	Yaml
	// JSON config
	JSON
)

type ErrorTao

type ErrorTao interface {
	error
	Code() string
	Wrap(err error)
	Cause() error
}

ErrorTao extension of error, wrap of error

func NewError

func NewError(code, message string, a ...interface{}) ErrorTao

NewError constructor of ErrorTao

type ErrorUnWrapper

type ErrorUnWrapper interface {
	error
	Unwrap() error
}

ErrorUnWrapper describe error which can be unwrapped

func NewErrorWrapped added in v0.0.3

func NewErrorWrapped(format string, e error) ErrorUnWrapper

NewErrorWrapped constructor of errorWrapped

type Factory added in v0.2.0

type Factory[T any] interface {
	Get(name string) (T, error)
	Has(name string) bool
	Names() []string
}

Factory 通用工厂接口

type Instance added in v0.2.1

type Instance[C any] struct {
	Name string
	Cfg  C
}

Instance 表示一个有序实例条目

type Log added in v0.0.2

type Log struct {
	Level     LogLevel `json:"level"`
	Type      LogType  `json:"type"`
	Flag      LogFlag  `json:"flag"`
	CallDepth int      `json:"call_depth"`
	Path      string   `json:"path,omitempty"`
	Disable   bool     `json:"disable"`
}

Log config in tao

type LogFlag added in v0.1.4

type LogFlag int

LogFlag log's flag

func (LogFlag) MarshalText added in v0.1.4

func (l LogFlag) MarshalText() ([]byte, error)

MarshalText instead of number

func (LogFlag) String added in v0.1.4

func (l LogFlag) String() string

String for LogType Config

func (*LogFlag) UnmarshalText added in v0.1.4

func (l *LogFlag) UnmarshalText(text []byte) error

UnmarshalText to number

type LogLevel

type LogLevel uint8

LogLevel log's level

const (
	// DEBUG (usually) is used in development env to print track info but disabled in production env to avoid overweight logs
	DEBUG LogLevel = iota
	// INFO (usually) is default level to print some core infos
	INFO
	// WARNING should be mentioned, it's more important than INFO
	WARNING
	// ERROR must be solved, program shouldn't generate any error-level logs.
	ERROR
	// PANIC logs a message, then panics.
	PANIC
	// FATAL logs a message, then calls os.Exit(1).
	FATAL
)

func (LogLevel) MarshalText added in v0.0.3

func (l LogLevel) MarshalText() ([]byte, error)

MarshalText instead of number

func (LogLevel) String added in v0.0.3

func (l LogLevel) String() string

String for LogLevel Config

func (*LogLevel) UnmarshalText added in v0.0.3

func (l *LogLevel) UnmarshalText(text []byte) error

UnmarshalText to number

type LogType added in v0.0.2

type LogType uint8

LogType log's type

const (
	// Console log
	Console LogType = 1 // 0b1
	// File log
	File LogType = 2 // 0b10
)

func (LogType) MarshalText added in v0.0.3

func (l LogType) MarshalText() ([]byte, error)

MarshalText instead of number

func (LogType) String added in v0.0.3

func (l LogType) String() string

String for LogType Config

func (*LogType) UnmarshalText added in v0.0.3

func (l *LogType) UnmarshalText(text []byte) error

UnmarshalText to number

type Logger

type Logger interface {
	Debug(v ...interface{})
	Debugf(format string, v ...interface{})
	Info(v ...interface{})
	Infof(format string, v ...interface{})
	Warn(v ...interface{})
	Warnf(format string, v ...interface{})
	Error(v ...interface{})
	Errorf(format string, v ...interface{})
	Panic(v ...interface{})
	Panicf(format string, v ...interface{})
	Fatal(v ...interface{})
	Fatalf(format string, v ...interface{})
}

Logger in tao

func GetLogger added in v0.0.3

func GetLogger(configKey string) Logger

GetLogger in tao

type MultiConfig added in v0.2.0

type MultiConfig[C any] interface {
	Config
	GetInstances() []Instance[C]
	SetInstances(instances []Instance[C])
	GetDefaultInstanceName() string
	SetDefaultInstanceName(name string)
}

MultiConfig 支持多实例的配置接口

type Parameter

type Parameter interface {
	Get(key string) (val interface{})
	Set(key string, val interface{})
	Clone() Parameter
	Delete(key string)
	String() string
}

Parameter describe function input or output

func NewParameter

func NewParameter() Parameter

NewParameter constructor of Parameter

type PipeTask added in v0.1.0

type PipeTask struct {
	Task
	// contains filtered or unexported fields
}

PipeTask task in Pipeline

func NewPipeTask

func NewPipeTask(task Task, runAfter ...string) *PipeTask

NewPipeTask constructor of PipeTask

type Pipeline

type Pipeline interface {
	Task
	Register(task *PipeTask) error
}

Pipeline to run tasks in order pipeline is also a task

func NewPipeline

func NewPipeline(name string, options ...PipelineOption) Pipeline

NewPipeline constructor of Pipeline

type PipelineOption

type PipelineOption func(p *pipeline)

PipelineOption optional function of pipeline

func SetPostStartTask

func SetPostStartTask(t *PipeTask) PipelineOption

SetPostStartTask of pipeline

func SetPreStopTask

func SetPreStopTask(t *PipeTask) PipelineOption

SetPreStopTask of pipeline

type Task

type Task interface {
	Name() string
	Run(ctx context.Context, param Parameter) error
	Result() Parameter
	Error() string
	Close() error
	State() TaskState
}

Task single Task

func NewTask

func NewTask(name string, fun TaskRun, options ...TaskOption) Task

NewTask constructor of Task

type TaskOption

type TaskOption func(t *task)

TaskOption optional function of task

func SetClose

func SetClose(cf func() error) TaskOption

SetClose of task

func SetPostStart

func SetPostStart(tr TaskRun) TaskOption

SetPostStart of task

func SetPreStop

func SetPreStop(tr TaskRun) TaskOption

SetPreStop of task

type TaskRun

type TaskRun func(ctx context.Context, param Parameter) (Parameter, error)

TaskRun with param

type TaskState

type TaskState uint8

TaskState to describe state of task

const (
	// Runnable task
	Runnable TaskState = iota
	// Running task
	Running
	// Over task
	Over
	// Closed task
	Closed
)

type Universe added in v0.1.2

type Universe struct {
	sync.WaitGroup

	Pipeline // main pipeline (for tao.Run())
	// contains filtered or unexported fields
}

Universe of tao

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL