MySLP_Customer_List_Cache
in package
Bounded, network-wide page cache with a live database gate and fixed daily expiry.
Page payloads are separate hash fields, not one serialized customer dataset. A companion sorted set tracks least-recently-used pages. Lua keeps the manifest, byte budget, entry budget, generation checks and publication atomic.
Table of Contents
Constants
- CLAIM : string = <<<'LUA' if redis.call('HGET', KEYS[1], '_gener...
- Read a page or acquire the expiring rebuild lease atomically.
- GATE : string = <<<'LUA' local now = tonumber(redis.call('TIME'...
- A changed site ID, completion token, expiry, or partial eviction resets both bounded keys. Hits do not extend expiry. No session keys are involved.
- LOCK_TTL : int = 120
- PUBLISH : string = <<<'LUA' if redis.call('HGET', KEYS[1], '_gener...
- Enforce byte/count budgets across all page variants and stats atomically.
- RELEASE : string = <<<'LUA' if redis.call('GET', KEYS[1]) == ARGV[...
- REVISION_OPTION : string = 'myslp_customer_cache_revision'
- SCHEMA : int = 1
- TTL : int = 86400
Properties
- $config : array<string|int, mixed>
- $network_id : int
- $prefix : string
- $store : MySLP_Cache_Valkey
Methods
- __construct() : mixed
- Cache connections are lazy; creating the service does not contact Valkey.
- invalidate() : bool
- Durable invalidation survives a temporary Valkey outage during signup.
- remember() : array<string|int, mixed>
- Return a shared neutral payload, or build it once if this request owns a miss.
- observe() : void
- Optional instrumentation contains timing/state only, never search/customer data.
- signal() : array<string|int, mixed>|null
- Fresh SQL deliberately bypasses WP/object caches on every lookup.
- uncached() : array<string|int, mixed>
Constants
CLAIM
Read a page or acquire the expiring rebuild lease atomically.
private
string
CLAIM
= <<<'LUA'
if redis.call('HGET', KEYS[1], '_generation') ~= ARGV[1]
or tonumber(redis.call('HGET', KEYS[1], '_count') or '0') ~= redis.call('ZCARD', KEYS[2]) then
return {'changed'}
end
local page = redis.call('HGET', KEYS[1], ARGV[2])
if page then
redis.call('ZADD', KEYS[2], redis.call('HINCRBY', KEYS[1], '_sequence', 1), ARGV[2])
return {'hit', page}
end
if redis.call('SET', KEYS[3], ARGV[3], 'NX', 'EX', ARGV[4]) then
return {'build'}
end
return {'wait'}
LUA
GATE
A changed site ID, completion token, expiry, or partial eviction resets both bounded keys. Hits do not extend expiry. No session keys are involved.
private
string
GATE
= <<<'LUA'
local now = tonumber(redis.call('TIME')[1])
local expires = tonumber(redis.call('HGET', KEYS[1], '_expires') or '0')
local count = tonumber(redis.call('HGET', KEYS[1], '_count') or '0')
if expires <= now
or redis.call('HGET', KEYS[1], '_site') ~= ARGV[1]
or redis.call('HGET', KEYS[1], '_revision') ~= ARGV[2]
or count ~= redis.call('ZCARD', KEYS[2]) then
redis.call('DEL', KEYS[1], KEYS[2])
expires = now + tonumber(ARGV[4])
redis.call('HSET', KEYS[1], '_generation', ARGV[3], '_site', ARGV[1],
'_revision', ARGV[2], '_created', now, '_expires', expires,
'_count', 0, '_bytes', 0, '_sequence', 0)
redis.call('EXPIREAT', KEYS[1], expires)
end
return redis.call('HGET', KEYS[1], '_generation')
LUA
LOCK_TTL
private
int
LOCK_TTL
= 120
PUBLISH
Enforce byte/count budgets across all page variants and stats atomically.
private
string
PUBLISH
= <<<'LUA'
if redis.call('HGET', KEYS[1], '_generation') ~= ARGV[1]
or redis.call('GET', KEYS[3]) ~= ARGV[3] then return 0 end
local expires = tonumber(redis.call('HGET', KEYS[1], '_expires') or '0')
if expires <= tonumber(redis.call('TIME')[1]) then return 0 end
local size = string.len(ARGV[4])
local max_count = tonumber(ARGV[5])
local max_bytes = tonumber(ARGV[6])
if size > max_bytes then return 0 end
local bytes = tonumber(redis.call('HGET', KEYS[1], '_bytes') or '0')
local count = tonumber(redis.call('HGET', KEYS[1], '_count') or '0')
if count ~= redis.call('ZCARD', KEYS[2]) then return 0 end
local old = redis.call('HGET', KEYS[1], ARGV[2])
if old then
bytes = bytes - string.len(old)
count = count - 1
redis.call('HDEL', KEYS[1], ARGV[2])
redis.call('ZREM', KEYS[2], ARGV[2])
end
while count >= max_count or bytes + size > max_bytes do
local oldest = redis.call('ZRANGE', KEYS[2], 0, 0)[1]
if not oldest then return 0 end
bytes = bytes - redis.call('HSTRLEN', KEYS[1], oldest)
count = count - 1
redis.call('HDEL', KEYS[1], oldest)
redis.call('ZREM', KEYS[2], oldest)
end
redis.call('HSET', KEYS[1], ARGV[2], ARGV[4], '_bytes', bytes + size, '_count', count + 1)
redis.call('ZADD', KEYS[2], redis.call('HINCRBY', KEYS[1], '_sequence', 1), ARGV[2])
redis.call('EXPIREAT', KEYS[2], expires)
return 1
LUA
RELEASE
private
string
RELEASE
= <<<'LUA'
if redis.call('GET', KEYS[1]) == ARGV[1] then
return redis.call('DEL', KEYS[1])
end
return 0
LUA
REVISION_OPTION
private
string
REVISION_OPTION
= 'myslp_customer_cache_revision'
SCHEMA
private
int
SCHEMA
= 1
TTL
private
int
TTL
= 86400
Properties
$config
private
array<string|int, mixed>
$config
$network_id
private
int
$network_id
$prefix
private
string
$prefix
$store
private
MySLP_Cache_Valkey
$store
Methods
__construct()
Cache connections are lazy; creating the service does not contact Valkey.
public
__construct() : mixed
invalidate()
Durable invalidation survives a temporary Valkey outage during signup.
public
static invalidate([int|null $network_id = null ]) : bool
Call only after customer writes have completed, or for an explicit refresh.
Parameters
- $network_id : int|null = null
Return values
boolremember()
Return a shared neutral payload, or build it once if this request owns a miss.
public
remember(array<string|int, mixed> $parameters, callable $build) : array<string|int, mixed>
Exceptions from the data builder propagate; cache errors alone fail open.
Parameters
- $parameters : array<string|int, mixed>
- $build : callable
Return values
array<string|int, mixed>observe()
Optional instrumentation contains timing/state only, never search/customer data.
private
observe(string $state, float $started) : void
Parameters
- $state : string
- $started : float
signal()
Fresh SQL deliberately bypasses WP/object caches on every lookup.
private
signal() : array<string|int, mixed>|null
The completion revision closes the site-created/customer-not-ready window.
Return values
array<string|int, mixed>|nulluncached()
private
uncached(callable $build, string $state, float $started) : array<string|int, mixed>
Parameters
- $build : callable
- $state : string
- $started : float