Skip to content

Commit

Permalink
Merge branch 'master' of github.com:jkyberneees/fast-gateway
Browse files Browse the repository at this point in the history
  • Loading branch information
jkyberneees committed May 29, 2019
2 parents fa3a56b + 00938e0 commit 9606a3a
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 7 deletions.
120 changes: 120 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,126 @@ service.start(3000)
}]
}
```
## Gateway level caching
### Why?
> Because `caching` is the last mile for low latency distributed systems!
Enabling proper caching strategies at gateway level will drastically reduce the latency of your system,
as it reduces network round-trips and remote services processing.
We are talking here about improvements in response times from `X ms` to `~2ms`, as an example.

### Setting up gateway level cache available for all services
#### Single node cache (memory):
```js
// cache middleware
const cache = require('http-cache-middleware')()
// enable http cache middleware
const gateway = require('fast-gateway')
const server = gateway({
middlewares: [cache],
routes: [...]
})
```
> Memory storage is recommended if there is only one gateway instance and you are not afraid of losing cache data.
#### Multi nodes cache (redis):
```js
// redis setup
const CacheManager = require('cache-manager')
const redisStore = require('cache-manager-ioredis')
const redisCache = CacheManager.caching({
store: redisStore,
db: 0,
host: 'localhost',
port: 6379,
ttl: 30
})

// cache middleware
const cache = require('http-cache-middleware')({
stores: [redisCache]
})

// enable http cache middleware
const gateway = require('fast-gateway')
const server = gateway({
middlewares: [cache],
routes: [...]
})
```
> Required if there are more than one gateway instances
### Enabling cache for service endpoints
Although API Gateway level cache aims as a centralized cache for all services behind the wall, are the services
the ones who indicate the responses to be cached and for how long.

Cache entries will be created for all remote responses coming with the `x-cache-timeout` header:
```js
res.setHeader('x-cache-timeout', '1 hour')
```
> Here we use the [`ms`](`https://www.npmjs.com/package/ms`) package to convert timeout to seconds. Please note that `millisecond` unit is not supported!
Example on remote service using `restana`:
```js
service.get('/numbers', (req, res) => {
res.setHeader('x-cache-timeout', '1 hour')

res.send([
1, 2, 3
])
})
```

### Invalidating cache
> Let's face it, gateway level cache invalidation was complex..., until now!
Remote services can also expire cache entries on demand, i.e: when the data state changes. Here we use the `x-cache-expire` header to indicate the gateway cache entries to expire using a matching pattern:
```js
res.setHeader('x-cache-expire', '*/numbers')
```
> Here we use the [`matcher`](`https://www.npmjs.com/package/matcher`) package for matching patterns evaluation.
Example on remote service using `restana`:
```js
service.patch('/numbers', (req, res) => {
res.setHeader('x-cache-expire', '*/numbers')

// ...
res.send(200)
})
```

### Custom cache keys
Cache keys are generated using: `req.method + req.url`, however, for indexing/segmenting requirements it makes sense to allow cache keys extensions.
Unfortunately, this feature can't be implemented at remote service level, because the gateway needs to know the entire lookup key when a request
reaches the gateway.

For doing this, we simply recommend using middlewares on the service configuration:
```js
routes: [{
prefix: '/users',
target: 'http://localhost:3000',
middlewares: [(req, res, next) => {
req.cacheAppendKey = (req) => req.user.id // here cache key will be: req.method + req.url + req.user.id
return next()
}]
}]
```
> In this example we also distinguish cache entries by `user.id`, very common case!
### Disable cache for custom endpoints
You can also disable cache checks for certain requests programmatically:
```js
routes: [{
prefix: '/users',
target: 'http://localhost:3000',
middlewares: [(req, res, next) => {
req.cacheDisabled = true
return next()
}]
}]
```

## Want to contribute?
This is your repo ;)

Expand Down
74 changes: 68 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"homepage": "https://github.com/jkyberneees/fast-gateway#readme",
"dependencies": {
"fast-proxy": "^1.1.0",
"http-cache-middleware": "^1.0.0",
"restana": "^3.0.2"
},
"devDependencies": {
Expand Down
5 changes: 4 additions & 1 deletion test/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ const pump = require('pump')

module.exports = async () => {
return {
middlewares: [require('cors')()],
middlewares: [
require('cors')(),
require('http-cache-middleware')()
],

routes: [{
pathRegex: '',
Expand Down

0 comments on commit 9606a3a

Please sign in to comment.