cache

The cache middleware provides cache data management for Flame instances, supporting various storage backends, including memory, file, PostgreSQL, MySQL, Redis and MongoDB.

You can read source code of this middleware on GitHubcache - 图1open in new window and API documentation on pkg.go.devcache - 图2open in new window.

Installation

The minimum requirement of Go is 1.16.

  1. go get github.com/flamego/cache

Storage backends

Memory

The cache.Cachercache - 图3open in new window works out-of-the-box with an optional cache.Optionscache - 图4open in new window and uses memory as the storage backend:

  1. package main
  2. import (
  3. "net/http"
  4. "time"
  5. "github.com/flamego/cache"
  6. "github.com/flamego/flamego"
  7. )
  8. func main() {
  9. f := flamego.Classic()
  10. f.Use(cache.Cacher())
  11. f.Get("/set", func(r *http.Request, cache cache.Cache) error {
  12. return cache.Set(r.Context(), "cooldown", true, time.Minute)
  13. })
  14. f.Get("/get", func(r *http.Request, cache cache.Cache) string {
  15. v, err := cache.Get(r.Context(), "cooldown")
  16. if err != nil && err != os.ErrNotExist {
  17. return err.Error()
  18. }
  19. cooldown, ok := v.(bool)
  20. if !ok || !cooldown {
  21. return "It has been cooled"
  22. }
  23. return "Still hot"
  24. })
  25. f.Run()
  26. }

Because the memory is volatile, cache data do not survive over restarts. Choose other storage backends if you need to persist cache data.

File

The cache.FileInitercache - 图5open in new window is the function to initialize a file storage backend, used together with cache.FileConfigcache - 图6open in new window to customize the backend:

  1. package main
  2. import (
  3. "net/http"
  4. "os"
  5. "path/filepath"
  6. "time"
  7. "github.com/flamego/cache"
  8. "github.com/flamego/flamego"
  9. )
  10. func main() {
  11. f := flamego.Classic()
  12. f.Use(cache.Cacher(
  13. cache.Options{
  14. Initer: cache.FileIniter(),
  15. Config: cache.FileConfig{
  16. RootDir: filepath.Join(os.TempDir(), "cache"),
  17. },
  18. },
  19. ))
  20. f.Get("/set", func(r *http.Request, cache cache.Cache) error {
  21. return cache.Set(r.Context(), "cooldown", true, time.Minute)
  22. })
  23. f.Get("/get", func(r *http.Request, cache cache.Cache) string {
  24. v, err := cache.Get(r.Context(), "cooldown")
  25. if err != nil && err != os.ErrNotExist {
  26. return err.Error()
  27. }
  28. cooldown, ok := v.(bool)
  29. if !ok || !cooldown {
  30. return "It has been cooled"
  31. }
  32. return "Still hot"
  33. })
  34. f.Run()
  35. }

PostgreSQL

The postgres.Initercache - 图7open in new window is the function to initialize a PostgreSQL storage backend, used together with postgres.Configcache - 图8open in new window to customize the backend:

  1. package main
  2. import (
  3. "net/http"
  4. "os"
  5. "time"
  6. "github.com/flamego/cache"
  7. "github.com/flamego/cache/postgres"
  8. "github.com/flamego/flamego"
  9. )
  10. func main() {
  11. f := flamego.Classic()
  12. dsn := os.ExpandEnv("postgres://$PGUSER:$PGPASSWORD@$PGHOST:$PGPORT/$PGDATABASE?sslmode=$PGSSLMODE")
  13. f.Use(cache.Cacher(
  14. cache.Options{
  15. Initer: postgres.Initer(),
  16. Config: postgres.Config{
  17. DSN: dsn,
  18. Table: "cache",
  19. InitTable: true,
  20. },
  21. },
  22. ))
  23. f.Get("/set", func(r *http.Request, cache cache.Cache) error {
  24. return cache.Set(r.Context(), "cooldown", true, time.Minute)
  25. })
  26. f.Get("/get", func(r *http.Request, cache cache.Cache) string {
  27. v, err := cache.Get(r.Context(), "cooldown")
  28. if err != nil && err != os.ErrNotExist {
  29. return err.Error()
  30. }
  31. cooldown, ok := v.(bool)
  32. if !ok || !cooldown {
  33. return "It has been cooled"
  34. }
  35. return "Still hot"
  36. })
  37. f.Run()
  38. }

MySQL

The mysql.Initercache - 图9open in new window is the function to initialize a MySQL storage backend, used together with mysql.Configcache - 图10open in new window to customize the backend:

  1. package main
  2. import (
  3. "net/http"
  4. "os"
  5. "time"
  6. "github.com/flamego/cache"
  7. "github.com/flamego/cache/mysql"
  8. "github.com/flamego/flamego"
  9. )
  10. func main() {
  11. f := flamego.Classic()
  12. dsn := os.ExpandEnv("$MYSQL_USER:$MYSQL_PASSWORD@tcp($MYSQL_HOST:$MYSQL_PORT)/$MYSQL_DATABASE?charset=utf8&parseTime=true")
  13. f.Use(cache.Cacher(
  14. cache.Options{
  15. Initer: mysql.Initer(),
  16. Config: mysql.Config{
  17. DSN: dsn,
  18. Table: "cache",
  19. InitTable: true,
  20. },
  21. },
  22. ))
  23. f.Get("/set", func(r *http.Request, cache cache.Cache) error {
  24. return cache.Set(r.Context(), "cooldown", true, time.Minute)
  25. })
  26. f.Get("/get", func(r *http.Request, cache cache.Cache) string {
  27. v, err := cache.Get(r.Context(), "cooldown")
  28. if err != nil && err != os.ErrNotExist {
  29. return err.Error()
  30. }
  31. cooldown, ok := v.(bool)
  32. if !ok || !cooldown {
  33. return "It has been cooled"
  34. }
  35. return "Still hot"
  36. })
  37. f.Run()
  38. }

Redis

The redis.Initercache - 图11open in new window is the function to initialize a Redis storage backend, used together with redis.Configcache - 图12open in new window to customize the backend:

  1. package main
  2. import (
  3. "net/http"
  4. "os"
  5. "time"
  6. "github.com/flamego/cache"
  7. "github.com/flamego/cache/redis"
  8. "github.com/flamego/flamego"
  9. )
  10. func main() {
  11. f := flamego.Classic()
  12. f.Use(cache.Cacher(
  13. cache.Options{
  14. Initer: redis.Initer(),
  15. Config: redis.Config{
  16. Options: &redis.Options{
  17. Addr: os.ExpandEnv("$REDIS_HOST:$REDIS_PORT"),
  18. DB: 15,
  19. },
  20. },
  21. },
  22. ))
  23. f.Get("/set", func(r *http.Request, cache cache.Cache) error {
  24. return cache.Set(r.Context(), "cooldown", true, time.Minute)
  25. })
  26. f.Get("/get", func(r *http.Request, cache cache.Cache) string {
  27. v, err := cache.Get(r.Context(), "cooldown")
  28. if err != nil && err != os.ErrNotExist {
  29. return err.Error()
  30. }
  31. cooldown, ok := v.(bool)
  32. if !ok || !cooldown {
  33. return "It has been cooled"
  34. }
  35. return "Still hot"
  36. })
  37. f.Run()
  38. }

MongoDB

The mongo.Initercache - 图13open in new window is the function to initialize a MongoDB storage backend, used together with mongo.Configcache - 图14open in new window to customize the backend:

  1. package main
  2. import (
  3. "net/http"
  4. "os"
  5. "time"
  6. "github.com/flamego/cache"
  7. "github.com/flamego/cache/mongo"
  8. "github.com/flamego/flamego"
  9. "go.mongodb.org/mongo-driver/mongo/options"
  10. )
  11. func main() {
  12. f := flamego.Classic()
  13. f.Use(cache.Cacher(
  14. cache.Options{
  15. Initer: mongo.Initer(),
  16. Config: mongo.Config{
  17. Options: options.Client().ApplyURI(os.Getenv("MONGODB_URI")),
  18. Database: os.Getenv("MONGODB_DATABASE"),
  19. Collection: "cache",
  20. },
  21. },
  22. ))
  23. f.Get("/set", func(r *http.Request, cache cache.Cache) error {
  24. return cache.Set(r.Context(), "cooldown", true, time.Minute)
  25. })
  26. f.Get("/get", func(r *http.Request, cache cache.Cache) string {
  27. v, err := cache.Get(r.Context(), "cooldown")
  28. if err != nil && err != os.ErrNotExist {
  29. return err.Error()
  30. }
  31. cooldown, ok := v.(bool)
  32. if !ok || !cooldown {
  33. return "It has been cooled"
  34. }
  35. return "Still hot"
  36. })
  37. f.Run()
  38. }

Supported value types

The default encoder and decoder of cache data use gobcache - 图15open in new window, and only limited types are supported for values. When you encounter errors like encode: gob: type not registered for interface: time.Duration, you can use gob.Registercache - 图16open in new window to register the type for encoding and decoding.

For example:

  1. gob.Register(time.Duration(0))

You only need to regsiter once for the entire lifecyle of your application.