{"id":13636666,"url":"https://github.com/hamishforbes/lua-resty-tlc","last_synced_at":"2025-10-28T11:30:43.584Z","repository":{"id":143139890,"uuid":"45242709","full_name":"hamishforbes/lua-resty-tlc","owner":"hamishforbes","description":"General two level cache (lrucache + shared dict)","archived":false,"fork":false,"pushed_at":"2017-04-19T13:30:20.000Z","size":15,"stargazers_count":19,"open_issues_count":1,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-02-14T06:36:01.901Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hamishforbes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2015-10-30T09:51:03.000Z","updated_at":"2024-02-14T06:36:01.902Z","dependencies_parsed_at":null,"dependency_job_id":"d14fa604-5a40-4b60-bc88-e272e46522d1","html_url":"https://github.com/hamishforbes/lua-resty-tlc","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamishforbes%2Flua-resty-tlc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamishforbes%2Flua-resty-tlc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamishforbes%2Flua-resty-tlc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hamishforbes%2Flua-resty-tlc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hamishforbes","download_url":"https://codeload.github.com/hamishforbes/lua-resty-tlc/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238638369,"owners_count":19505579,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T00:01:03.864Z","updated_at":"2025-10-28T11:30:43.266Z","avatar_url":"https://github.com/hamishforbes.png","language":"Perl","funding_links":[],"categories":["Libraries"],"sub_categories":[],"readme":"# lua-resty-tlc\n\nTwo Layer Cache implementation using [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache) and [shared dictionaries](https://github.com/openresty/lua-nginx-module#ngxshareddict).\n\nCache entries are written to lru-cache in the current worker and to a shared dictionary.\n\nCache reads that miss in the worker's lru-cache instance are re-populated from the shared dictionary if available.\n\nValues in shared dictionaries are automatically serialised and unserialised to JSON (custom serialisation functions are supported)\n\nAlso provides a manager module to maintain global set of TLC cache instances\n\n# Overview\n\n```lua\nlua_package_path \"/path/to/lua-resty-tlc/lib/?.lua;;\";\n\nlua_shared_dict tlc_cache 10m;\nlua_shared_dict tlc_cache2 1m;\n\ninit_by_lua_block {\n    local manager = require(\"resty.tlc.manager\")\n    manager.new(\"my_cache\", {size = 500, dict = \"tlc_cache\"})\n\n    manager.new(\"my_cache2\", {size = 500, dict = \"tlc_cache2\"})\n}\n\n\nlocation = /get {\n    content_by_lua_block {\n        local manager = require(\"resty.tlc.manager\")\n        local cache = manager.get(\"my_cache\")\n\n        local args = ngx.req.get_uri_args()\n        local key = args[\"key\"]\n\n        local data, err = cache:get(key)\n        if err then\n            ngx.log(ngx.ERR, err)\n        elseif data == nil then\n            ngx.status = ngx.HTTP_NOT_FOUND\n            ngx.say(\"Not Found\")\n        else\n            ngx.say(tostring(data))\n        end\n    }\n}\n\nlocation = /set {\n    content_by_lua_block {\n        local manager = require(\"resty.tlc.manager\")\n        local cache = manager.get(\"my_cache\")\n\n        local args = ngx.req.get_uri_args()\n        local key = args[\"key\"]\n        local val = args[\"val\"] or { foo = bar }\n        local ttl = args[\"ttl\"]\n\n        local ok, err = cache:set(key, val, ttl)\n        if not ok then\n            ngx.log(ngx.ERR, err)\n        end\n    }\n}\n\nlocation = /flush {\n    content_by_lua_block {\n        local manager = require(\"resty.tlc.manager\")\n        local cache = manager.get(\"my_cache\")\n        cache:flush()\n    }\n}\n\nlocation = /list {\n    content_by_lua_block {\n        local manager = require(\"resty.tlc.manager\")\n        local instances = manager.list()\n\n        ngx.say(require(\"cjson\").encode(instances))\n    }\n}\n\n\n```\n\n# Methods\n\n* [manager](#manager)\n * [new](#new)\n * [get](#get)\n * [set](#set)\n * [delete](#delete)\n * [list](#list)\n* [cache](#cache)\n * [new](#new-1)\n * [set](#set-1)\n * [get](#get-1)\n * [delete](#delete-1)\n * [flush](#flush)\n\n## manager\n\n### new\n`syntax: ok, err = manager.new(name, opts)`\n\nCreate a new `resty.tlc.cache` instance with given name/id and options.\n\nWill **not** check if instance already exists, existing instances will be overwritten\n\n### get\n`syntax: cache = manager.get(name)`\n\nReturns the specified TLC cache instance or nil\n\n### delete\n`syntax: manager.delete(name)`\n\nRemoves the specified cache instance.\n\n### list\n`syntax: instances = manager.list()`\n\nReturns an array table of available cache instances\n\n## cache\n\n### new\n`syntax: instance = cache:new(opts)`\n\nCreates a new instance of `resty.tlc.cache`, `opts` is a table of options for this instance.\n\n```lua\nopts = {\n    dict         = dict,         -- Shared dictionary name, required\n    size         = size,         -- max_items parameter for LRU cache, optional, default 200\n    pureffi      = pureffi,      -- Use the pureffi LRU cache variant, optional, default false\n    loadfactor   = loadfactor,   -- Load factor for pureffi LRU cache, optional\n    serialiser   = serialiser,   -- Function to serialise values when saving to shared dictionary, optional, defaults to pcall'd cjson encode\n    unserialiser = unserialiser, -- Function to unserialise values when saving to shared dictionary, optional, defaults to pcall'd cjson decode\n}\n```\n\nFunctions to serialise and unserialise should `return nil, err` on failure.\n\n### set\n`syntax: ok, err = cache:set(key, value, ttl?)`\n\nSet or update an entry in the cache.\n\n`ttl` is optional and in seconds\n\n\n### get\n`syntax: data = cache:get(key)`\n\nReturns data from cache or `nil` if not set\n\n\n### delete\n`syntax: cache:delete(key)`\n\nDeletes entry from both LRU cache and shared dictionary\n\nTODO: Delete from LRU cache in all workers\n\n### flush\n`syntax: cache:flush(hard?)`\n\nRe-initialises LRU cache in current worker and flushes shared dictionary.\n\n`hard` argument will also call `flush_expired()` on dictionary.\n\nTODO: Re-initialise LRU cache in all workers\n\n\n# TODO\n\n* Add feature to ngx_lua shared dictionary to retrieve remaining TTL of entry\n* Syncronise LRU cache delete / flush across workers\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhamishforbes%2Flua-resty-tlc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhamishforbes%2Flua-resty-tlc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhamishforbes%2Flua-resty-tlc/lists"}