Go: cache s napojením na externí zdroje

Dopsal jsem 1. verzi své multicache. Asi nejvýznamnějším rozšířením je její integrace na externí zdroje.

Cache můžete plnit skrze resources, což jsou jednoduché funkce pro získávání dat z jakéhokoliv datově zajímavého vstupu. Implementace je postaná na closurech s myšlenkou oddělit logiku samotné cache od procesu získávání dat.

Volání funkcionality pro loadování dat je zabaleno do gorutiny a korektnost synchronizace je pak zajištěna mutexem.

Na Go je pěkné, jak jde všechno jednoduše napsat. Go je blízko C, takže kód je stručný a jasný. Vedle toho closures, GC a ostatní fíčury z něj dělají opravdy efektivní jazyk pro psaní bezpečných, performance náročných aplikací.

Zdroják je volně dostupný na GitHubu pod GPL licencí.

package main

import (
    "caching/cache"
    "caching/resources"
    "fmt"
    "log"

    _ "github.com/lib/pq"
)

// configs for external resources, should be replaced
// in productin by deploy mechanism (reading from env, etc...)
var ro = resources.RedisOptions{Addr: "localhost:6379"}
var po = resources.PostgreOptions{
    Host:     "localhost",
    User:     "",
    Password: "",
    Db:       "",
    Query:    "SELECT key, value FROM cities",
}
var citiesFile = "./data/cities.json"

type cacheConfig struct {
    name   string
    loader func() (cache.KeyValueStore, error)
    ttl    int64
}


var cfg = [...]cacheConfig{{
    name:   "cities",
    loader: resources.JSONFile(citiesFile),
    ttl:    2000,
}, {
    name:   "states",
    loader: resources.Static(),
    ttl:    2000,
}, {
    name:   "fruits",
    loader: resources.Redis(ro),
    ttl:    2000,
}, {
    name:   "flight",
    loader: resources.Postgresql(po),
    ttl:    2000,
}}

func main() {

    c := make(cache.Cache)

    fmt.Println("LOADING DATA 2 CACHE")
    for _, cc := range cfg {
        num, err := c.Create(cc.name, cc.loader, cc.ttl)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("cache %s: loaded %d items\n", cc.name, num)
    }

    fmt.Printf("\nREADING FROM CACHES\n")

    // look for a key in specific cache
    cName := "states"
    key := "CZ"
    if val, ok := c.Get(cName, key); ok {
        fmt.Printf("[%s] %s => \"%s\"\n", cName, key, val)
    }

    // look for a key across all caches
    key = "CZ"
    pepa := c.FindAll(key)
    if len(pepa) > 0 {
        for i, v := range pepa {
            fmt.Printf("[%s] %s => \"%s\"\n", i, key, v)
        }
    }

}