Skip to content

Commit

Permalink
add doc for panic
Browse files Browse the repository at this point in the history
  • Loading branch information
ktong committed Jan 31, 2024
1 parent 0262da8 commit cf0d354
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 14 deletions.
41 changes: 32 additions & 9 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"log/slog"
"strings"
"sync"
"time"

"github.com/go-viper/mapstructure/v2"

Expand Down Expand Up @@ -67,10 +68,11 @@ func New(opts ...Option) *Config {
// Each loader takes precedence over the loaders before it.
//
// This method can be called multiple times but it is not concurrency-safe.
// It panics if any loader is nil.
func (c *Config) Load(loaders ...Loader) error {
for i, loader := range loaders {
if loader == nil {
panic(fmt.Sprintf("nil loader at loaders[%d]", i))
panic(fmt.Sprintf("cannot load config from nil loader at loaders[%d]", i))

Check warning on line 75 in config.go

View check run for this annotation

Codecov / codecov/patch

config.go#L75

Added line #L75 was not covered by tests
}

values, err := loader.Load()
Expand Down Expand Up @@ -101,9 +103,10 @@ func (c *Config) Load(loaders ...Loader) error {
// WARNING: All loaders passed in Load after calling Watch do not get watched.
//
// It only can be called once. Call after first has no effects.
// It panics if ctx is nil.
func (c *Config) Watch(ctx context.Context) error { //nolint:cyclop,funlen,gocognit
if ctx == nil {
panic("nil context")
panic("cannot watch change with nil context")

Check warning on line 109 in config.go

View check run for this annotation

Codecov / codecov/patch

config.go#L109

Added line #L109 was not covered by tests
}

watched := true
Expand Down Expand Up @@ -136,12 +139,30 @@ func (c *Config) Watch(ctx context.Context) error { //nolint:cyclop,funlen,gocog
c.values = values
slog.Info("Configuration has been updated with change.")

// TODO: detect blocking onChange and return error.
for _, onChange := range onChanges {
onChange(c)
}
if len(onChanges) > 0 {
slog.Info("Configuration has been applied to onChanges.")
func() {
ctx, cancel = context.WithTimeout(context.Background(), time.Minute)
defer cancel()

done := make(chan struct{})
go func() {
defer close(done)

for _, onChange := range onChanges {
onChange(c)
}
}()

select {
case <-done:
slog.InfoContext(ctx, "Configuration has been applied to onChanges.")
case <-ctx.Done():
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
slog.WarnContext(ctx, "Configuration has not been applied to onChanges due to timeout."+
" Please check if the onChanges is blocking or takes too long to complete.")
}

Check warning on line 163 in config.go

View check run for this annotation

Codecov / codecov/patch

config.go#L159-L163

Added lines #L159 - L163 were not covered by tests
}
}()
}

case <-ctx.Done():
Expand Down Expand Up @@ -235,12 +256,14 @@ func sub(values map[string]any, path string, delimiter string) any {
// It requires Config.Watch has been called first.
// The paths are case-insensitive.
//
// TODO: add requirement for onchange function, like non-blocking,
// The onChange function must be non-blocking and usually completes instantly.
// If it requires a long time to complete, it should be executed in a separate goroutine.
//
// This method is concurrency-safe.
// It panics if onChange is nil.
func (c *Config) OnChange(onChange func(*Config), paths ...string) {
if onChange == nil {
panic("nil onChange")
panic("cannot register nil onChange")

Check warning on line 266 in config.go

View check run for this annotation

Codecov / codecov/patch

config.go#L266

Added line #L266 was not covered by tests
}

c.onChangesMutex.Lock()
Expand Down
10 changes: 8 additions & 2 deletions default.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,24 @@ func Unmarshal(path string, target any) error {
// OnChange registers a callback function that is executed
// when the value of any given path in the default Config changes.
// The paths are case-insensitive.
// TODO: add requirement for onchange function, like non-blocking,
//
// The onChange function must be non-blocking and usually completes instantly.
// If it requires a long time to complete, it should be executed in a separate goroutine.
//
// This method is concurrency-safe.
// It panics if onChange is nil.
func OnChange(onChange func(), paths ...string) {
defaultConfig.Load().OnChange(func(*Config) { onChange() }, paths...)
}

// SetDefault sets the given Config as the default Config.
// After this call, the konf package's top functions (e.g. konf.Get)
// will interact with the given Config.
//
// It panics if config is nil.
func SetDefault(config *Config) {
if config == nil {
panic("nil config")
panic("cannot set default with nil config")

Check warning on line 58 in default.go

View check run for this annotation

Codecov / codecov/patch

default.go#L58

Added line #L58 was not covered by tests
}

defaultConfig.Store(config)
Expand Down
4 changes: 3 additions & 1 deletion provider/file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ type File struct {
}

// New creates a File with the given path and Option(s).
//
// It panics if the path is empty.
func New(path string, opts ...Option) File {
if path == "" {
panic("empty path")
panic("cannot create File with empty path")

Check warning on line 37 in provider/file/file.go

View check run for this annotation

Codecov / codecov/patch

provider/file/file.go#L37

Added line #L37 was not covered by tests
}

option := &options{
Expand Down
6 changes: 4 additions & 2 deletions provider/fs/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@ type FS struct {
}

// New creates a FS with the given fs.FS, path and Option(s).
//
// It panics if the fs is nil or the path is empty.
func New(fs fs.FS, path string, opts ...Option) FS { //nolint:varnamelen
if fs == nil {
panic("nil fs")
panic("cannot create FS with nil fs")

Check warning on line 39 in provider/fs/fs.go

View check run for this annotation

Codecov / codecov/patch

provider/fs/fs.go#L39

Added line #L39 was not covered by tests
}
if path == "" {
panic("empty path")
panic("cannot create FS with empty path")

Check warning on line 42 in provider/fs/fs.go

View check run for this annotation

Codecov / codecov/patch

provider/fs/fs.go#L42

Added line #L42 was not covered by tests
}

option := &options{
Expand Down

0 comments on commit cf0d354

Please sign in to comment.