Skip to content

Commit

Permalink
feat: Create Singleton func for convenient singleton construction (#1297
Browse files Browse the repository at this point in the history
)

Fixes issue #1295

---------

Co-authored-by: Alec Thomas <[email protected]>
  • Loading branch information
deniseli and alecthomas authored Apr 18, 2024
1 parent ba3c6e7 commit 794a835
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 0 deletions.
27 changes: 27 additions & 0 deletions go-runtime/ftl/singleton.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package ftl

import (
"context"
"sync"
)

type SingletonHandle[T any] struct {
fn func(context.Context) (T, error)
out T
once *sync.Once
}

func (sh *SingletonHandle[T]) Get(ctx context.Context) T {
sh.once.Do(func() {
t, err := sh.fn(ctx)
if err != nil {
panic(err)
}
sh.out = t
})
return sh.out
}

func Singleton[T any](fn func(context.Context) (T, error)) SingletonHandle[T] {
return SingletonHandle[T]{fn: fn, once: &sync.Once{}}
}
33 changes: 33 additions & 0 deletions go-runtime/ftl/singleton_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package ftl

import (
"context"
"fmt"
"testing"

"github.com/alecthomas/assert/v2"
)

func TestSingletonBaseCase(t *testing.T) {
incrementer := 0

ctx := context.Background()
once := Singleton[string](func(ctx context.Context) (string, error) {
incrementer++
return "only once", nil
})

assert.Equal(t, once.Get(ctx), "only once")
assert.Equal(t, once.Get(ctx), "only once")
assert.Equal(t, incrementer, 1)
}

func TestSingletonPanic(t *testing.T) {
ctx := context.Background()
once := Singleton[string](func(ctx context.Context) (string, error) {
return "", fmt.Errorf("test error")
})
assert.Panics(t, func() {
once.Get(ctx)
})
}

0 comments on commit 794a835

Please sign in to comment.