Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions cmd/cachewd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/alecthomas/hcl/v2"
"github.com/alecthomas/kong"

"github.com/block/cachew/internal/cache"
"github.com/block/cachew/internal/config"
"github.com/block/cachew/internal/httputil"
"github.com/block/cachew/internal/jobscheduler"
Expand All @@ -36,10 +37,15 @@ func main() {
ctx := context.Background()
logger, ctx := logging.Configure(ctx, cli.LoggingConfig)

cr := cache.NewRegistry()
cache.RegisterMemory(cr)
cache.RegisterDisk(cr)
cache.RegisterS3(cr)

// Commands
switch { //nolint:gocritic
case cli.Schema:
schema := config.Schema()
schema := config.Schema(cr)
slices.SortStableFunc(schema.Entries, func(a, b hcl.Entry) int {
return strings.Compare(a.EntryKey(), b.EntryKey())
})
Expand All @@ -59,7 +65,7 @@ func main() {

scheduler := jobscheduler.New(ctx, cli.SchedulerConfig)

err := config.Load(ctx, cli.Config, scheduler, mux, parseEnvars())
err := config.Load(ctx, cr, cli.Config, scheduler, mux, parseEnvars())
kctx.FatalIfErrorf(err)

logger.InfoContext(ctx, "Starting cachewd", slog.String("bind", cli.Bind))
Expand Down
22 changes: 15 additions & 7 deletions internal/cache/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,29 @@ type registryEntry struct {
factory func(ctx context.Context, config *hcl.Block) (Cache, error)
}

var registry = map[string]registryEntry{}
type Registry struct {
registry map[string]registryEntry
}

func NewRegistry() *Registry {
return &Registry{
registry: make(map[string]registryEntry),
}
}

// Factory is a function that creates a new cache instance from the given hcl-tagged configuration struct.
type Factory[Config any, C Cache] func(ctx context.Context, config Config) (C, error)

// Register a cache factory function.
func Register[Config any, C Cache](id, description string, factory Factory[Config, C]) {
func Register[Config any, C Cache](r *Registry, id, description string, factory Factory[Config, C]) {
var c Config
schema, err := hcl.BlockSchema(id, &c)
if err != nil {
panic(err)
}
block := schema.Entries[0].(*hcl.Block) //nolint:errcheck // This seems spurious
block.Comments = hcl.CommentList{description}
registry[id] = registryEntry{
r.registry[id] = registryEntry{
schema: block,
factory: func(ctx context.Context, config *hcl.Block) (Cache, error) {
var cfg Config
Expand All @@ -51,9 +59,9 @@ func Register[Config any, C Cache](id, description string, factory Factory[Confi
}

// Schema returns the schema for all registered cache backends.
func Schema() *hcl.AST {
func (r *Registry) Schema() *hcl.AST {
ast := &hcl.AST{}
for _, entry := range registry {
for _, entry := range r.registry {
ast.Entries = append(ast.Entries, entry.schema)
}
return ast
Expand All @@ -62,8 +70,8 @@ func Schema() *hcl.AST {
// Create a new cache instance from the given name and configuration.
//
// Will return "ErrNotFound" if the cache backend is not found.
func Create(ctx context.Context, name string, config *hcl.Block) (Cache, error) {
if entry, ok := registry[name]; ok {
func (r *Registry) Create(ctx context.Context, name string, config *hcl.Block) (Cache, error) {
if entry, ok := r.registry[name]; ok {
return errors.WithStack2(entry.factory(ctx, config))
}
return nil, errors.Errorf("%s: %w", name, ErrNotFound)
Expand Down
4 changes: 3 additions & 1 deletion internal/cache/disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ import (
"github.com/block/cachew/internal/logging"
)

func init() {
// RegisterDisk cache with the given registry.
func RegisterDisk(r *Registry) {
Register(
r,
"disk",
"Caches objects on local disk, with a maximum size limit and LRU eviction",
NewDisk,
Expand Down
3 changes: 2 additions & 1 deletion internal/cache/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ import (
"github.com/block/cachew/internal/logging"
)

func init() {
func RegisterMemory(r *Registry) {
Register(
r,
"memory",
"Caches objects in memory, with a maximum size limit and LRU eviction",
NewMemory,
Expand Down
3 changes: 2 additions & 1 deletion internal/cache/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ import (
"github.com/block/cachew/internal/logging"
)

func init() {
func RegisterS3(r *Registry) {
Register(
r,
"s3",
"Caches objects in S3",
NewS3,
Expand Down
8 changes: 4 additions & 4 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ func (l *loggingMux) HandleFunc(pattern string, handler func(http.ResponseWriter
var _ strategy.Mux = (*loggingMux)(nil)

// Schema returns the configuration file schema.
func Schema() *hcl.AST {
func Schema(cr *cache.Registry) *hcl.AST {
return &hcl.AST{
Entries: append(strategy.Schema().Entries, cache.Schema().Entries...),
Entries: append(strategy.Schema().Entries, cr.Schema().Entries...),
}
}

// Load HCL configuration and uses that to construct the cache backend, and proxy strategies.
func Load(ctx context.Context, r io.Reader, scheduler jobscheduler.Scheduler, mux *http.ServeMux, vars map[string]string) error {
func Load(ctx context.Context, cr *cache.Registry, r io.Reader, scheduler jobscheduler.Scheduler, mux *http.ServeMux, vars map[string]string) error {
logger := logging.FromContext(ctx)
ast, err := hcl.Parse(r)
if err != nil {
Expand All @@ -63,7 +63,7 @@ func Load(ctx context.Context, r io.Reader, scheduler jobscheduler.Scheduler, mu
for _, node := range ast.Entries {
switch node := node.(type) {
case *hcl.Block:
c, err := cache.Create(ctx, node.Name, node)
c, err := cr.Create(ctx, node.Name, node)
if errors.Is(err, cache.ErrNotFound) {
strategyCandidates = append(strategyCandidates, node)
continue
Expand Down