Last active
April 19, 2017 21:21
-
-
Save pintsized/4353981 to your computer and use it in GitHub Desktop.
Ledge state machine idea
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
lsm_mod = require("lsm") | |
lsm = lsm_mod:new("checking_request_accepts_cache") -- Pass in initial state | |
-- ACTIONS --------------------------------- | |
lsm:action("redis_connect", function() | |
print("#a: Connecting to redis") | |
end) | |
lsm:action("redis_close", function() | |
print("#a: Closing redis connection") | |
end) | |
lsm:action("read_cache", function() | |
print("#a: Reading cache from Redis") | |
res = { | |
status = 200, | |
header = { | |
["Content-Type"] = "text/plain", | |
}, | |
body = "Hello, from Cache" | |
} | |
end) | |
lsm:action("fetch", function() | |
print("#a: Fetching from origin") | |
if only_if_cached then | |
res.status = 504 | |
else | |
res = { header = {}, status = 200, body = "Hello, from Origin" } | |
end | |
end) | |
lsm:action("remove_client_validators", function() | |
print("#a: Removing client validators") | |
end) | |
lsm:action("add_stale_warning", function() | |
print("#a: 110 Response is stale") | |
end) | |
lsm:action("serve", function() | |
print("#a: Serving") | |
print(res.status) | |
for f,v in pairs(res.header) do | |
print(f .. ": " .. v) | |
end | |
print(res.body) | |
end) | |
lsm:action("background_revalidate", function() | |
print("#a: Starting background revalidation") | |
end) | |
lsm:action("update_cache", function() | |
print("#a: Updating cache") | |
end) | |
-- BEFORE TRANS ------------------------ | |
lsm:before_transition({ to = "checking_request_accepts_cache", action = "redis_connect" }) | |
lsm:before_transition({ to = "exiting", action = "redis_close" }) | |
lsm:before_transition({ to = "serving_stale", action = "add_stale_warning" }) | |
-- EVENTS ------------------------------------- | |
lsm:event("cache_accepted", { | |
{ when = "checking_request_accepts_cache", begin = "checking_cache", but_first = "read_cache" }, | |
{ when = "validating_locally", begin = "serving" } | |
}) | |
lsm:event("cache_not_accepted", { | |
{ when = "checking_request_accepts_cache", begin = "fetching" } | |
}) | |
lsm:event("cache_missing", { | |
{ when = "checking_cache", begin = "fetching", but_first = "remove_client_validators" } | |
}) | |
lsm:event("cache_expired", { | |
{ when = "checking_cache", begin = "checking_can_serve_stale" }, | |
{ when = "checking_can_serve_stale", begin = "fetching", but_first = "remove_client_validators" } | |
}) | |
lsm:event("cache_valid", { | |
{ when = "checking_cache", begin = "considering_revalidation" } | |
}) | |
lsm:event("response_fetched", { | |
{ begin = "serving", but_first = "update_cache" } | |
}) | |
lsm:event("must_revalidate", { | |
{ when = "considering_revalidation", begin = "considering_local_revalidation" }, | |
{ when = "considering_local_revalidation", begin = "revalidating_upstream" }, | |
}) | |
lsm:event("can_revalidate_locally", { | |
{ begin = "revalidating_locally" }, | |
}) | |
lsm:event("not_modified", { | |
{ when = "revalidating_locally", begin = "serving_not_modified" }, | |
{ when = "re_revalidating_locally", begin = "serving_not_modified" }, | |
{ when = "revalidating_upstream", begin = "re_revalidating_locally" }, | |
{ when = "revalidating_in_background", begin = "exiting" }, | |
}) | |
lsm:event("modified", { | |
{ when = "revalidating_locally", begin = "revalidating_upstream" }, | |
{ when = "re_revalidating_locally", begin = "serving" }, | |
{ when = "revalidating_upstream", begin = "re_revalidating_locally", but_first = "update_cache" }, | |
{ when = "revalidating_in_background", begin = "exiting", but_first = "update_cache" } | |
}) | |
lsm:event("serve_stale", { | |
{ when = "checking_can_serve_stale", begin = "serving_stale" } | |
}) | |
lsm:event("served", { | |
{ when = "serving_stale", begin = "revalidating_in_background" }, | |
{ begin = "exiting" }, | |
}) | |
-- STATES ------------------------------ | |
lsm:state("checking_request_accepts_cache", function() | |
local req = req() | |
if req.cache_accepted == true then | |
return lsm:cache_accepted() | |
else | |
return lsm:cache_not_accepted() | |
end | |
end) | |
lsm:state("checking_cache", function() | |
local res = read() | |
if not res then | |
return lsm:cache_missing() | |
elseif res.expired then | |
return lsm:cache_expired() | |
else | |
return lsm:cache_valid() | |
end | |
end) | |
lsm:state("fetching", function() | |
local res = fetch() | |
if res.status == 304 then | |
return lsm:can_serve() | |
else | |
return lsm:response_fetched() | |
end | |
end) | |
lsm:state("considering_revalidation", function() | |
return lsm:must_revalidate() | |
end) | |
lsm:state("considering_local_revalidation", function() | |
return lsm:can_revalidate_locally() | |
end) | |
lsm:state("revalidating_locally", function() | |
return lsm:modified() | |
end) | |
lsm:state("re_revalidating_locally", function() | |
return lsm:not_modified() | |
--return lsm:modified() | |
end) | |
lsm:state("revalidating_upstream", function() | |
return lsm:modified() | |
--return lsm:not_modified() | |
end) | |
lsm:state("revalidating_in_background", function() | |
-- return lsm:modified() | |
return lsm:not_modified() | |
end) | |
lsm:state("checking_can_serve_stale", function() | |
return lsm:serve_stale() | |
--return lsm:cache_expired() | |
end) | |
lsm:state("serving", function() | |
return lsm:served() | |
end) | |
lsm:state("serving_not_modified", function() | |
return lsm:served() | |
end) | |
lsm:state("serving_stale", function() | |
return lsm:served() | |
end) | |
lsm:state("exiting", function() | |
end) | |
-- Go | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module("lsm", package.seeall) | |
local mt = { | |
-- Expose all events as functions | |
__index = function(t, k) | |
if t.events[k] then | |
return t.events[k] | |
else | |
return _M[k] | |
end | |
end | |
} | |
function new(self, initial) | |
return setmetatable({ | |
current_state = nil, | |
initial_state = initial, | |
events = {}, | |
states = {}, | |
actions = {}, | |
before_transitions = {}, | |
}, mt) | |
end | |
function event(self, ev, transition_table) | |
assert(not self.events[ev], "#e: Cannot redefine event '" .. ev .. "'") | |
self.events[ev] = function() | |
for _,trans in ipairs(transition_table) do | |
if trans["when"] == nil or trans["when"] == self.current_state then | |
assert(trans["begin"], "#e: Nothing to begin after '" .. ev .. "' when '" .. self.current_state .. "'") | |
print("#e: " .. ev) | |
if trans["but_first"] then | |
assert("function" == type(self.actions[trans["but_first"]]), "No action function defined for '" .. trans["but_first"] .. "'") | |
self.actions[trans["but_first"]]() | |
end | |
return self:transition(trans["begin"]) | |
end | |
end | |
print("#e: ERROR: No transitions found for " .. ev .. " when " .. self.current_state) | |
end | |
end | |
function state(self, st, func) | |
self.states[st] = func | |
end | |
function action(self, ac, func) | |
self.actions[ac] = func | |
end | |
function before_transition(self, rule) | |
self.before_transitions[rule["to"]] = { from = rule["from"], action = rule["action"] } | |
end | |
function transition(self, state) | |
assert("function" == type(self.states[state]), "State '" .. state .. "' function not defined") | |
-- Check for any transition pre-tasks | |
local before_t = self.before_transitions[state] | |
if before_t and (before_t["from"] == nil or self.current_state == before_t["from"]) then | |
assert("function" == type(self.actions[before_t["action"]]), | |
"Action " .. before_t["action"] .. " is not a function") | |
self.actions[before_t["action"]]() | |
end | |
print("#t: " .. state) | |
self.current_state = state | |
return self.states[self.current_state]() | |
end | |
function start(self) | |
self:transition(self.initial_state) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment