mirror of
https://github.com/kataras/iris.git
synced 2025-03-13 21:36:28 +01:00
Update to 5.0.2 - Cache(only) improvements
Cache - only improvements
This commit is contained in:
parent
948eb2ecc1
commit
8b88aabc05
15
HISTORY.md
15
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`.
|
||||
|
||||
## 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
|
||||
|
||||
|
@ -371,7 +382,7 @@ type WebsocketConfiguration struct {
|
|||
|
||||
```
|
||||
|
||||
- **REMOVE**: `github.com/kataras/iris/context/context.go` , this is no needed anymore. Its only usage was inside `sessions` and `websockets`, a month ago I did improvements to the sessions as a standalone package, the IContext interface is not being used there. With the today's changes, the iris-contrib/websocket doesn't needs the IContext interface too, so the whole folder `./context` is useless and removed now. Users developers don't have any side-affects from this change.
|
||||
- **REMOVE**: `github.com/kataras/iris/context/context.go` , this is no needed anymore. Its only usage was inside `sessions` and `websockets`, a month ago I did improvements to the sessions as a standalone package, the IContext interface is not being used there. With the today's changes, the iris-contrib/websocket doesn't needs the IContext interface too, so the whole folder `./context` is useless and removed now. Users developers don't have any side-affects from this change.
|
||||
|
||||
|
||||
[Examples](https://github.com/iris-contrib/examples), [Book](https://github.com/iris-contrib/gitbook) are up-to-date, just new configuration fields.
|
||||
|
@ -835,7 +846,7 @@ OptionServerVScheme(val string)
|
|||
// You're free to change it, but I will trust you to don't, this is the only setting whose somebody, like me, can see if iris web framework is used
|
||||
OptionServerName(val string)
|
||||
|
||||
```
|
||||
```
|
||||
|
||||
View all configuration fields and options by navigating to the [kataras/iris/configuration.go source file](https://github.com/kataras/iris/blob/master/configuration.go)
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<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>
|
||||
|
||||
|
@ -825,7 +825,7 @@ I recommend writing your API tests using this new library, [httpexpect](https://
|
|||
Versioning
|
||||
------------
|
||||
|
||||
Current: **v5.0.1**
|
||||
Current: **v5.0.2**
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
gzipEnabled := ctx.framework.Config.Gzip
|
||||
charset := ctx.framework.Config.Charset
|
||||
if len(options) > 0 {
|
||||
|
@ -1131,11 +1130,6 @@ func (ctx *Context) MaxAge() int64 {
|
|||
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
|
||||
func (ctx *Context) Log(format string, a ...interface{}) {
|
||||
ctx.framework.Logger.Printf(format, a...)
|
||||
|
|
27
http.go
27
http.go
|
@ -13,6 +13,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/geekypanda/httpcache"
|
||||
"github.com/iris-contrib/letsencrypt"
|
||||
"github.com/kataras/go-errors"
|
||||
"github.com/valyala/fasthttp"
|
||||
|
@ -696,9 +697,29 @@ func (e *muxEntry) precedenceTo(index int) int {
|
|||
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 (
|
||||
// Route contains some useful information about a route
|
||||
|
|
62
http_test.go
62
http_test.go
|
@ -11,10 +11,12 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gavv/httpexpect"
|
||||
"github.com/kataras/go-errors"
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/httptest"
|
||||
"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")
|
||||
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"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
|
@ -65,8 +66,6 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"bytes"
|
||||
"github.com/geekypanda/httpcache"
|
||||
"github.com/kataras/go-errors"
|
||||
"github.com/kataras/go-fs"
|
||||
"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 = false
|
||||
// Version is the current version number of the Iris web framework
|
||||
Version = "5.0.1"
|
||||
Version = "5.0.2"
|
||||
|
||||
banner = ` _____ _
|
||||
|_ _| (_)
|
||||
|
@ -167,7 +166,6 @@ type (
|
|||
TemplateSourceString(string, interface{}) string
|
||||
SerializeToString(string, interface{}, ...map[string]interface{}) string
|
||||
Cache(HandlerFunc, time.Duration) HandlerFunc
|
||||
InvalidateCache(*Context)
|
||||
}
|
||||
|
||||
// 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){
|
||||
// ctx.WriteString("Hello, world!") // or a template or anything else
|
||||
// }, 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.
|
||||
// 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(),
|
||||
// use the app.Cache instead of iris.Cache
|
||||
func (s *Framework) Cache(bodyHandler HandlerFunc, expiration time.Duration) HandlerFunc {
|
||||
fh := httpcache.Fasthttp.Cache(func(reqCtx *fasthttp.RequestCtx) {
|
||||
ctx := s.AcquireCtx(reqCtx)
|
||||
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)
|
||||
ce := newCachedMuxEntry(s, bodyHandler, expiration)
|
||||
return ce.Serve
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue
Block a user