Skip to content

Commit 34d4468

Browse files
authored
Merge pull request #5 from strongloop/nginx-honour-cache-expiration
NGINX: fix cache expiration
2 parents 82ce02f + 992a041 commit 34d4468

File tree

2 files changed

+28
-34
lines changed

2 files changed

+28
-34
lines changed

ephemeral-npm.lua

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,30 @@ local cjson = require "cjson.safe"
22

33
local _M = {}
44

5+
local function parseDuration(str)
6+
-- TODO: parse inputs like "1h", "2d", "10m" and return them as seconds
7+
return 5 * 60
8+
end
9+
510
function _M.init()
611
local npmConfig = ngx.shared.npmConfig
7-
local registry = os.getenv("npm_config_registry"):gsub("/+$", "")
8-
local pattern = registry:gsub("%.", "%%."):gsub("%-", "%%-")
12+
_M.registry = os.getenv("npm_config_registry"):gsub("/+$", "")
13+
_M.hostPattern = _M.registry:gsub("%.", "%%."):gsub("%-", "%%-")
14+
_M.MAXAGE = parseDuration(os.getenv("MAXAGE") or "5m")
915
-- escape . and - which have special meaning in Lua patterns
10-
npmConfig:set('npm_config_registry', registry)
11-
npmConfig:set('npm_upstream_pattern', pattern)
16+
npmConfig:set('npm_config_registry', _M.registry)
17+
npmConfig:set('npm_upstream_pattern', _M.hostPattern)
18+
npmConfig:set('MAXAGE', _M.MAXAGE)
1219
end
1320

1421
function _M.getPackage()
1522
local uri = ngx.var.uri
1623
local meta = ngx.shared.npmMeta
1724
local body = meta:get(uri)
25+
local base = ngx.var.scheme .. '://' .. ngx.var.http_host
1826
-- yep, our own shared memory cache implementation :-/
1927
if body == nil then
28+
ngx.var.ephemeralCacheStatus = 'MISS'
2029
local res = ngx.location.capture('/-@-' .. uri,
2130
{ copy_all_vars = true })
2231
body = res.body
@@ -27,19 +36,13 @@ function _M.getPackage()
2736
-- next time
2837
return ngx.redirect(uri, ngx.HTTP_MOVED_TEMPORARILY)
2938
end
30-
meta:set(uri, body)
39+
meta:set(uri, body, _M.MAXAGE)
40+
else
41+
ngx.var.ephemeralCacheStatus = 'HIT'
3142
end
43+
body = string.gsub(body, _M.hostPattern, base)
3244
ngx.header["Content-Length"] = #body
3345
ngx.print(body)
3446
end
3547

36-
function _M.filterPackageBody()
37-
local npmConfig = ngx.shared.npmConfig
38-
local upstream = npmConfig:get('npm_upstream_pattern')
39-
-- need to construct URL because we may be proxying http<->https
40-
local base = ngx.var.scheme .. '://' .. ngx.var.http_host
41-
-- ngx.log(ngx.ERR, "Modifying JSON of " .. ngx.var.uri .. " to replace '" .. upstream .. "' with '" .. base .. "'")
42-
ngx.arg[1] = string.gsub(ngx.arg[1], upstream, base)
43-
end
44-
4548
return _M

nginx.conf

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,17 @@ events {
1111
http {
1212
# We literally only care about 2 types of files/payloads.
1313
types {
14-
application/json json;
1514
application/gzip tgz;
1615
}
17-
default_type application/octet-stream;
16+
default_type application/json;
1817
sendfile on;
1918
keepalive_timeout 65;
2019
proxy_cache_path /tmp/npm/cache levels=1:2 keys_zone=NPM:10m inactive=90d max_size=5g;
2120
proxy_temp_path /tmp/npm/temp;
2221
proxy_cache_lock on;
2322
log_format upstreamlog '$remote_addr - $remote_user [$time_local] '
2423
'"$request" $status $body_bytes_sent '
25-
'"$http_referer" "$http_user_agent" "$upstream_cache_status"';
24+
'"$http_referer" "$http_user_agent" "$ephemeralCacheStatus"';
2625
access_log logs/access.log upstreamlog;
2726

2827
lua_shared_dict npmConfig 32k;
@@ -32,7 +31,6 @@ http {
3231
local ephemeralNPM = require "ephemeral-npm"
3332
ephemeralNPM.init()
3433
}
35-
3634
server {
3735
listen 4873;
3836
set $npm_config_registry '';
@@ -44,34 +42,27 @@ http {
4442
try_files $uri @fetch-tgz;
4543
}
4644
location / {
45+
set $ephemeralCacheStatus '-';
46+
# We can't do caching at the proxy level because we can't easily
47+
# parameterize cache lifetime for proxy_cache. Instead, we do
48+
# the caching ourselves in Lua using a shared dict.
4749
content_by_lua_block {
4850
local ephemeralNPM = require "ephemeral-npm"
4951
ephemeralNPM.getPackage()
5052
}
5153
}
54+
# This is just a straight though, uncaching proxy to the upstream
55+
# registry.
56+
# We have to use a path prefix instead of an internal @name because
57+
# we need to be able to make sub-requests using ngx.location.capture()
5258
location /-@- {
5359
internal;
5460
rewrite /-@-/(.+) /$1 break;
5561
resolver 127.0.0.1 ipv6=off;
5662
proxy_pass $npm_config_registry;
5763
proxy_buffers 32 1m;
58-
proxy_cache NPM;
59-
# need nginx-1.11.10 for this, which isn't in openresty yet:
60-
# proxy_cache_background_update on;
61-
proxy_cache_revalidate on;
62-
# let our metadata be 20 minutes old, at most
63-
proxy_cache_valid 200 20m;
64-
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
65-
# need to disable encoding in order to be able to filter the response body
64+
# need to disable encoding in order to be able to process it locally
6665
proxy_set_header Accept-Encoding "";
67-
# modifying the response body will change the length
68-
header_filter_by_lua_block {
69-
ngx.header.content_length = nil
70-
}
71-
body_filter_by_lua_block {
72-
local ephemeralNPM = require "ephemeral-npm"
73-
ephemeralNPM.filterPackageBody()
74-
}
7566
}
7667
location @fetch-tgz {
7768
internal;

0 commit comments

Comments
 (0)