Lines of
counter.lua
from check-in 38ec946cba
that are changed by the sequence of edits moving toward
check-in b33171b487:
1: -- module counter - counts some junk
2:
38ec946cba 2014-07-03 3: local today = os.date('*t')
38ec946cba 2014-07-03 4: local timestamp = os.time{year = today['year'], month = today['month'], day = today['day']}
38ec946cba 2014-07-03 5: local referer = '-';
38ec946cba 2014-07-03 6:
38ec946cba 2014-07-03 7: if ngx.var.http_referer ~= nil then
38ec946cba 2014-07-03 8: _, _, referer = string.find(ngx.var.http_referer, '^https?://([%w%.]+)')
38ec946cba 2014-07-03 9: end
38ec946cba 2014-07-03 10:
38ec946cba 2014-07-03 11: local key = 'stat_counter_' .. timestamp .. '_' .. referer
12:
38ec946cba 2014-07-03 13: -- connect to redis
14: local redis = require 'resty.redis'
38ec946cba 2014-07-03 15: local red = redis:new()
38ec946cba 2014-07-03 16: local ok, err = red:connect('127.0.0.1', 6379)
38ec946cba 2014-07-03 17: if not ok then
38ec946cba 2014-07-03 18: ngx.log(ngx.ERR, 'redis connection failed: ', err)
38ec946cba 2014-07-03 19: ngx.exit(500)
38ec946cba 2014-07-03 20: end
38ec946cba 2014-07-03 21:
22: local cjson = require 'cjson'
23:
38ec946cba 2014-07-03 24: -- decodes values from array into dict
38ec946cba 2014-07-03 25: function decode_bulk(reply)
26: local data = {}
27: for j=1, #reply, 2 do
28: data[reply[j] ] = reply[j+1]
29: end
38ec946cba 2014-07-03 30: return(data)
38ec946cba 2014-07-03 31: end
38ec946cba 2014-07-03 32:
38ec946cba 2014-07-03 33: local data, empty
38ec946cba 2014-07-03 34: empty, err = red:hsetnx(key, 'today', 0)
38ec946cba 2014-07-03 35: if not empty then
38ec946cba 2014-07-03 36: ngx.log(ngx.ERR, 'redis query failed: ', err)
38ec946cba 2014-07-03 37: ngx.exit(500)
38ec946cba 2014-07-03 38: end
38ec946cba 2014-07-03 39:
38ec946cba 2014-07-03 40: if empty == 0 then
38ec946cba 2014-07-03 41: data, err = red:hgetall(key)
38ec946cba 2014-07-03 42: if not data then
38ec946cba 2014-07-03 43: ngx.log(ngx.ERR, 'redis query failed: ', err)
38ec946cba 2014-07-03 44: ngx.exit(500)
38ec946cba 2014-07-03 45: end
38ec946cba 2014-07-03 46: end
38ec946cba 2014-07-03 47:
38ec946cba 2014-07-03 48: if empty == 1 or data.whole == nil then
38ec946cba 2014-07-03 49: -- postgres fallback
38ec946cba 2014-07-03 50: result = ngx.location.capture('/postgres', {
38ec946cba 2014-07-03 51: method = ngx.HTTP_PUT,
38ec946cba 2014-07-03 52: body = "select * from get_stats('" .. referer .. "') as (today int, lastday int, week bigint, whole bigint);"
38ec946cba 2014-07-03 53: })
38ec946cba 2014-07-03 54: if result.status ~= 200 or not result.body then
38ec946cba 2014-07-03 55: ngx.log(ngx.ERR, 'postgres access failed')
38ec946cba 2014-07-03 56: ngx.exit(500)
38ec946cba 2014-07-03 57: else
38ec946cba 2014-07-03 58: local unrds = require "rds.parser"
38ec946cba 2014-07-03 59: local res, err = unrds.parse(result.body)
38ec946cba 2014-07-03 60: if res == nil then
38ec946cba 2014-07-03 61: ngx.log(ngx.ERR, 'failed to obtain data: ' .. err)
38ec946cba 2014-07-03 62: ngx.exit(500)
38ec946cba 2014-07-03 63: else
38ec946cba 2014-07-03 64: data = res.resultset[1]
38ec946cba 2014-07-03 65: local req = {key}
38ec946cba 2014-07-03 66:
38ec946cba 2014-07-03 67: for name, value in pairs(data) do
38ec946cba 2014-07-03 68: if value == unrds.null then
38ec946cba 2014-07-03 69: value = 0
38ec946cba 2014-07-03 70: end
38ec946cba 2014-07-03 71: if name ~= 'today' then
38ec946cba 2014-07-03 72: table.insert(req, name)
38ec946cba 2014-07-03 73: table.insert(req, value)
38ec946cba 2014-07-03 74: end
38ec946cba 2014-07-03 75: end
38ec946cba 2014-07-03 76:
38ec946cba 2014-07-03 77: red:init_pipeline(3)
38ec946cba 2014-07-03 78: red:hmset{req}
38ec946cba 2014-07-03 79: red:expire(key, 129600)
38ec946cba 2014-07-03 80: red:hincrby(key, 'today', data.today)
38ec946cba 2014-07-03 81: res, err = red:commit_pipeline()
38ec946cba 2014-07-03 82: if not res then
38ec946cba 2014-07-03 83: ngx.log(ngx.ERR, 'redis pipeline failed: ', err)
38ec946cba 2014-07-03 84: ngx.exit(500)
38ec946cba 2014-07-03 85: end
38ec946cba 2014-07-03 86: end
38ec946cba 2014-07-03 87: end
38ec946cba 2014-07-03 88: end
38ec946cba 2014-07-03 89:
38ec946cba 2014-07-03 90: data.today = data.today + 1
38ec946cba 2014-07-03 91: ngx.say(cjson.encode(data))
38ec946cba 2014-07-03 92: ngx.eof()
38ec946cba 2014-07-03 93:
38ec946cba 2014-07-03 94: res, err = red:hincrby(key, 'today', 1)
38ec946cba 2014-07-03 95: local uid = ''
38ec946cba 2014-07-03 96:
38ec946cba 2014-07-03 97: if ngx.var.uid_got ~= nil and string.find(ngx.var.uid_got, 'uid=') == 1 then
38ec946cba 2014-07-03 98: uid = string.sub(ngx.var.uid_got, 5)
38ec946cba 2014-07-03 99: elseif ngx.var.uid_set ~= nil and string.find(ngx.var.uid_set, 'uid=') == 1 then
38ec946cba 2014-07-03 100: uid = string.sub(ngx.var.uid_set, 5)
38ec946cba 2014-07-03 101: end
38ec946cba 2014-07-03 102:
38ec946cba 2014-07-03 103: local hit_key = uid .. '_' .. referer .. '_' .. ngx.var.remote_addr
38ec946cba 2014-07-03 104:
38ec946cba 2014-07-03 105: red:init_pipeline(5)
38ec946cba 2014-07-03 106: red:multi()
38ec946cba 2014-07-03 107: red:hincrby('stat_counter_pending', hit_key, 1)
38ec946cba 2014-07-03 108: red:expire('stat_counter_pending', 60)
38ec946cba 2014-07-03 109: red:renamenx('stat_counter_pending', 'stat_counter_pending_tmp')
38ec946cba 2014-07-03 110: red:exec()
38ec946cba 2014-07-03 111: renamed, err = red:commit_pipeline()
38ec946cba 2014-07-03 112: if not renamed then
38ec946cba 2014-07-03 113: ngx.log(ngx.ERR, 'redis multi failed: ', err)
38ec946cba 2014-07-03 114: ngx.exit(500)
38ec946cba 2014-07-03 115: end
38ec946cba 2014-07-03 116:
38ec946cba 2014-07-03 117: local continue = false
38ec946cba 2014-07-03 118: if tonumber(renamed[5][3]) == 1 then
38ec946cba 2014-07-03 119: continue = true
38ec946cba 2014-07-03 120: end
38ec946cba 2014-07-03 121:
38ec946cba 2014-07-03 122: while continue do
38ec946cba 2014-07-03 123: ngx.location.capture('/sleep')
38ec946cba 2014-07-03 124:
38ec946cba 2014-07-03 125: local data
38ec946cba 2014-07-03 126: data, err = red:hgetall('stat_counter_pending_tmp')
38ec946cba 2014-07-03 127: if not data then
38ec946cba 2014-07-03 128: ngx.log(ngx.ERR, 'redis request failed: ', err)
38ec946cba 2014-07-03 129: ngx.exit(500)
38ec946cba 2014-07-03 130: end
38ec946cba 2014-07-03 131:
38ec946cba 2014-07-03 132: for name, value in pairs(decode_bulk(data)) do
38ec946cba 2014-07-03 133: local fields = {}
38ec946cba 2014-07-03 134: name:gsub("[^_]+", function(c) fields[#fields + 1] = c end)
38ec946cba 2014-07-03 135: fields[#fields + 1] = value
38ec946cba 2014-07-03 136: local result = ngx.location.capture('/postgres', {
38ec946cba 2014-07-03 137: method = ngx.HTTP_PUT,
38ec946cba 2014-07-03 138: -- prepare select? XXX
38ec946cba 2014-07-03 139: body = "select merge_counter('" .. fields[1] .. "'::text, '" .. fields[2] .. "'::text, '" .. fields[3] .. "'::inet, '" .. fields[4] .. "'::smallint);"
38ec946cba 2014-07-03 140: })
38ec946cba 2014-07-03 141: if result.status ~= 200 or not result.body then
38ec946cba 2014-07-03 142: ngx.log(ngx.ERR, 'postgres access failed')
38ec946cba 2014-07-03 143: ngx.exit(500)
38ec946cba 2014-07-03 144: end
38ec946cba 2014-07-03 145: end
38ec946cba 2014-07-03 146:
38ec946cba 2014-07-03 147: red:init_pipeline(5)
38ec946cba 2014-07-03 148: red:multi()
38ec946cba 2014-07-03 149: red:del('stat_counter_pending_tmp')
38ec946cba 2014-07-03 150: red:exists('stat_counter_pending')
38ec946cba 2014-07-03 151: red:renamenx('stat_counter_pending', 'stat_counter_pending_tmp')
38ec946cba 2014-07-03 152: red:exec()
38ec946cba 2014-07-03 153: renamed, err = red:commit_pipeline()
38ec946cba 2014-07-03 154: if not renamed then
38ec946cba 2014-07-03 155: ngx.log(ngx.ERR, 'redis multi failed: ', err)
38ec946cba 2014-07-03 156: ngx.exit(500)
38ec946cba 2014-07-03 157: end
38ec946cba 2014-07-03 158:
38ec946cba 2014-07-03 159: if tonumber(renamed[5][1] == 0) or tonumber(renamed[5][2]) == 0 then
38ec946cba 2014-07-03 160: continue = false
38ec946cba 2014-07-03 161: end
38ec946cba 2014-07-03 162: end