mirror of
https://github.com/kataras/iris.git
synced 2025-03-15 04:06:25 +01:00
Update to 5.0.2 - Cache(only) improvements
Cache - only improvements
This commit is contained in:
parent
948eb2ecc1
commit
8b88aabc05
11
HISTORY.md
11
HISTORY.md
|
@ -2,6 +2,17 @@
|
||||||
|
|
||||||
**How to upgrade**: remove your `$GOPATH/src/github.com/kataras` folder, open your command-line and execute this command: `go get -u github.com/kataras/iris/iris`.
|
**How to upgrade**: remove your `$GOPATH/src/github.com/kataras` folder, open your command-line and execute this command: `go get -u github.com/kataras/iris/iris`.
|
||||||
|
|
||||||
|
## 5.0.1 -> 5.0.2
|
||||||
|
|
||||||
|
- [geekypanda/httpcache](https://github.com/geekypanda/httpcache) has been re-written,
|
||||||
|
by me, got rid of the mutex locks and use individual statcks instead,
|
||||||
|
gain even more performance boost
|
||||||
|
|
||||||
|
- `InvalidateCache` has been removed,
|
||||||
|
it wasn't working well for big apps, let cache work with
|
||||||
|
its automation, is better.
|
||||||
|
|
||||||
|
- Add tests for the `iris.Cache`
|
||||||
|
|
||||||
## v3 -> [v4](https://github.com/kataras/iris/tree/4.0.0) (fasthttp-based) long term support
|
## v3 -> [v4](https://github.com/kataras/iris/tree/4.0.0) (fasthttp-based) long term support
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
|
|
||||||
<a href="https://github.com/kataras/iris/releases"><img src="https://img.shields.io/badge/%20version%20-%205.0.1%20-blue.svg?style=flat-square" alt="Releases"></a>
|
<a href="https://github.com/kataras/iris/releases"><img src="https://img.shields.io/badge/%20version%20-%205.0.2%20-blue.svg?style=flat-square" alt="Releases"></a>
|
||||||
|
|
||||||
<a href="https://github.com/iris-contrib/examples"><img src="https://img.shields.io/badge/%20examples-repository-3362c2.svg?style=flat-square" alt="Examples"></a>
|
<a href="https://github.com/iris-contrib/examples"><img src="https://img.shields.io/badge/%20examples-repository-3362c2.svg?style=flat-square" alt="Examples"></a>
|
||||||
|
|
||||||
|
@ -825,7 +825,7 @@ I recommend writing your API tests using this new library, [httpexpect](https://
|
||||||
Versioning
|
Versioning
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Current: **v5.0.1**
|
Current: **v5.0.2**
|
||||||
|
|
||||||
Stable: **[v4 LTS](https://github.com/kataras/iris/tree/4.0.0#versioning)**
|
Stable: **[v4 LTS](https://github.com/kataras/iris/tree/4.0.0#versioning)**
|
||||||
|
|
||||||
|
|
|
@ -561,7 +561,6 @@ func (ctx *Context) renderSerialized(contentType string, obj interface{}, option
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
gzipEnabled := ctx.framework.Config.Gzip
|
gzipEnabled := ctx.framework.Config.Gzip
|
||||||
charset := ctx.framework.Config.Charset
|
charset := ctx.framework.Config.Charset
|
||||||
if len(options) > 0 {
|
if len(options) > 0 {
|
||||||
|
@ -1131,11 +1130,6 @@ func (ctx *Context) MaxAge() int64 {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
// InvalidateCache clears the cache manually for this request uri context's handler's route
|
|
||||||
func (ctx *Context) InvalidateCache() {
|
|
||||||
ctx.framework.InvalidateCache(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log logs to the iris defined logger
|
// Log logs to the iris defined logger
|
||||||
func (ctx *Context) Log(format string, a ...interface{}) {
|
func (ctx *Context) Log(format string, a ...interface{}) {
|
||||||
ctx.framework.Logger.Printf(format, a...)
|
ctx.framework.Logger.Printf(format, a...)
|
||||||
|
|
27
http.go
27
http.go
|
@ -13,6 +13,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/geekypanda/httpcache"
|
||||||
"github.com/iris-contrib/letsencrypt"
|
"github.com/iris-contrib/letsencrypt"
|
||||||
"github.com/kataras/go-errors"
|
"github.com/kataras/go-errors"
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
|
@ -696,9 +697,29 @@ func (e *muxEntry) precedenceTo(index int) int {
|
||||||
return newindex
|
return newindex
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// cachedMuxEntry is just a wrapper for the Cache functionality
|
||||||
//
|
// it seems useless but I prefer to keep the cached handler on its own memory stack,
|
||||||
//
|
// reason: no clojures hell in the Cache function
|
||||||
|
type cachedMuxEntry struct {
|
||||||
|
cachedHandler fasthttp.RequestHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCachedMuxEntry(f *Framework, bodyHandler HandlerFunc, expiration time.Duration) *cachedMuxEntry {
|
||||||
|
fhandler := func(reqCtx *fasthttp.RequestCtx) {
|
||||||
|
ctx := f.AcquireCtx(reqCtx)
|
||||||
|
bodyHandler.Serve(ctx)
|
||||||
|
f.ReleaseCtx(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedHandler := httpcache.CacheFasthttp(fhandler, expiration)
|
||||||
|
return &cachedMuxEntry{
|
||||||
|
cachedHandler: cachedHandler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cachedMuxEntry) Serve(ctx *Context) {
|
||||||
|
c.cachedHandler(ctx.RequestCtx)
|
||||||
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// Route contains some useful information about a route
|
// Route contains some useful information about a route
|
||||||
|
|
62
http_test.go
62
http_test.go
|
@ -11,10 +11,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gavv/httpexpect"
|
"github.com/gavv/httpexpect"
|
||||||
|
"github.com/kataras/go-errors"
|
||||||
"github.com/kataras/iris"
|
"github.com/kataras/iris"
|
||||||
"github.com/kataras/iris/httptest"
|
"github.com/kataras/iris/httptest"
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
|
@ -689,3 +691,63 @@ func TestMuxFireMethodNotAllowed(t *testing.T) {
|
||||||
e.POST("/mypath").Expect().Status(iris.StatusMethodNotAllowed).Body().Equal("Hello from my custom 405 page")
|
e.POST("/mypath").Expect().Status(iris.StatusMethodNotAllowed).Body().Equal("Hello from my custom 405 page")
|
||||||
iris.Close()
|
iris.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
cacheDuration = 5 * time.Second
|
||||||
|
errCacheTestFailed = errors.New("Expected the main handler to be executed %d times instead of %d.")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ~14secs
|
||||||
|
func runCacheTest(e *httpexpect.Expect, path string, counterPtr *uint32, expectedBodyStr, expectedContentType string) error {
|
||||||
|
e.GET(path).Expect().Status(iris.StatusOK).Body().Equal(expectedBodyStr)
|
||||||
|
time.Sleep(cacheDuration / 5) // lets wait for a while, cache should be saved and ready
|
||||||
|
e.GET(path).Expect().Status(iris.StatusOK).Body().Equal(expectedBodyStr)
|
||||||
|
counter := atomic.LoadUint32(counterPtr)
|
||||||
|
if counter > 1 {
|
||||||
|
// n should be 1 because it doesn't changed after the first call
|
||||||
|
return errCacheTestFailed.Format(1, counter)
|
||||||
|
}
|
||||||
|
time.Sleep(cacheDuration)
|
||||||
|
|
||||||
|
// cache should be cleared now
|
||||||
|
e.GET(path).Expect().Status(iris.StatusOK).ContentType(expectedContentType, "utf-8").Body().Equal(expectedBodyStr)
|
||||||
|
time.Sleep(cacheDuration / 5)
|
||||||
|
// let's call again , the cache should be saved
|
||||||
|
e.GET(path).Expect().Status(iris.StatusOK).ContentType(expectedContentType, "utf-8").Body().Equal(expectedBodyStr)
|
||||||
|
counter = atomic.LoadUint32(counterPtr)
|
||||||
|
if counter != 2 {
|
||||||
|
return errCacheTestFailed.Format(2, counter)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCache(t *testing.T) {
|
||||||
|
|
||||||
|
iris.ResetDefault()
|
||||||
|
|
||||||
|
expectedBodyStr := "Imagine it as a big message to achieve x20 response performance!"
|
||||||
|
var textCounter, htmlCounter uint32
|
||||||
|
|
||||||
|
iris.Get("/text", iris.Cache(func(ctx *iris.Context) {
|
||||||
|
atomic.AddUint32(&textCounter, 1)
|
||||||
|
ctx.Text(iris.StatusOK, expectedBodyStr)
|
||||||
|
}, cacheDuration))
|
||||||
|
|
||||||
|
iris.Get("/html", iris.Cache(func(ctx *iris.Context) {
|
||||||
|
atomic.AddUint32(&htmlCounter, 1)
|
||||||
|
ctx.HTML(iris.StatusOK, expectedBodyStr)
|
||||||
|
}, cacheDuration))
|
||||||
|
|
||||||
|
e := httptest.New(iris.Default, t)
|
||||||
|
|
||||||
|
// test cache on text/plain
|
||||||
|
if err := runCacheTest(e, "/text", &textCounter, expectedBodyStr, "text/plain"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// text cache on text/html
|
||||||
|
if err := runCacheTest(e, "/html", &htmlCounter, expectedBodyStr, "text/html"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
37
iris.go
37
iris.go
|
@ -52,6 +52,7 @@ visit https://www.gitbook.com/book/kataras/iris/details
|
||||||
package iris // import "github.com/kataras/iris"
|
package iris // import "github.com/kataras/iris"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
@ -65,8 +66,6 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"bytes"
|
|
||||||
"github.com/geekypanda/httpcache"
|
|
||||||
"github.com/kataras/go-errors"
|
"github.com/kataras/go-errors"
|
||||||
"github.com/kataras/go-fs"
|
"github.com/kataras/go-fs"
|
||||||
"github.com/kataras/go-serializer"
|
"github.com/kataras/go-serializer"
|
||||||
|
@ -81,7 +80,7 @@ const (
|
||||||
// IsLongTermSupport flag is true when the below version number is a long-term-support version
|
// IsLongTermSupport flag is true when the below version number is a long-term-support version
|
||||||
IsLongTermSupport = false
|
IsLongTermSupport = false
|
||||||
// Version is the current version number of the Iris web framework
|
// Version is the current version number of the Iris web framework
|
||||||
Version = "5.0.1"
|
Version = "5.0.2"
|
||||||
|
|
||||||
banner = ` _____ _
|
banner = ` _____ _
|
||||||
|_ _| (_)
|
|_ _| (_)
|
||||||
|
@ -167,7 +166,6 @@ type (
|
||||||
TemplateSourceString(string, interface{}) string
|
TemplateSourceString(string, interface{}) string
|
||||||
SerializeToString(string, interface{}, ...map[string]interface{}) string
|
SerializeToString(string, interface{}, ...map[string]interface{}) string
|
||||||
Cache(HandlerFunc, time.Duration) HandlerFunc
|
Cache(HandlerFunc, time.Duration) HandlerFunc
|
||||||
InvalidateCache(*Context)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Framework is our God |\| Google.Search('Greek mythology Iris')
|
// Framework is our God |\| Google.Search('Greek mythology Iris')
|
||||||
|
@ -1127,7 +1125,7 @@ func (s *Framework) SerializeToString(keyOrContentType string, obj interface{},
|
||||||
// Usage: iris.Get("/", iris.Cache(func(ctx *iris.Context){
|
// Usage: iris.Get("/", iris.Cache(func(ctx *iris.Context){
|
||||||
// ctx.WriteString("Hello, world!") // or a template or anything else
|
// ctx.WriteString("Hello, world!") // or a template or anything else
|
||||||
// }, time.Duration(10*time.Second))) // duration of expiration
|
// }, time.Duration(10*time.Second))) // duration of expiration
|
||||||
// if <=time.Second then it tries to find it though request header's "cache-control" maxage value
|
// if <=2 seconds then it tries to find it though request header's "cache-control" maxage value
|
||||||
//
|
//
|
||||||
// Note that it depends on a station instance's cache service.
|
// Note that it depends on a station instance's cache service.
|
||||||
// Do not try to call it from default' station if you use the form of app := iris.New(),
|
// Do not try to call it from default' station if you use the form of app := iris.New(),
|
||||||
|
@ -1146,33 +1144,8 @@ func Cache(bodyHandler HandlerFunc, expiration time.Duration) HandlerFunc {
|
||||||
// Do not try to call it from default' station if you use the form of app := iris.New(),
|
// Do not try to call it from default' station if you use the form of app := iris.New(),
|
||||||
// use the app.Cache instead of iris.Cache
|
// use the app.Cache instead of iris.Cache
|
||||||
func (s *Framework) Cache(bodyHandler HandlerFunc, expiration time.Duration) HandlerFunc {
|
func (s *Framework) Cache(bodyHandler HandlerFunc, expiration time.Duration) HandlerFunc {
|
||||||
fh := httpcache.Fasthttp.Cache(func(reqCtx *fasthttp.RequestCtx) {
|
ce := newCachedMuxEntry(s, bodyHandler, expiration)
|
||||||
ctx := s.AcquireCtx(reqCtx)
|
return ce.Serve
|
||||||
bodyHandler.Serve(ctx)
|
|
||||||
s.ReleaseCtx(ctx)
|
|
||||||
}, expiration)
|
|
||||||
|
|
||||||
return func(ctx *Context) {
|
|
||||||
fh(ctx.RequestCtx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvalidateCache clears the cache body for a specific context's url path(cache unique key)
|
|
||||||
//
|
|
||||||
// Note that it depends on a station instance's cache service.
|
|
||||||
// Do not try to call it from default' station if you use the form of app := iris.New(),
|
|
||||||
// use the app.InvalidateCache instead of iris.InvalidateCache
|
|
||||||
func InvalidateCache(ctx *Context) {
|
|
||||||
Default.InvalidateCache(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvalidateCache clears the cache body for a specific context's url path(cache unique key)
|
|
||||||
//
|
|
||||||
// Note that it depends on a station instance's cache service.
|
|
||||||
// Do not try to call it from default' station if you use the form of app := iris.New(),
|
|
||||||
// use the app.InvalidateCache instead of iris.InvalidateCache
|
|
||||||
func (s *Framework) InvalidateCache(ctx *Context) {
|
|
||||||
httpcache.Fasthttp.Invalidate(ctx.RequestCtx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue
Block a user