Draft preview · this lesson is still being technically validated. Browser experiments and reference material remain available; trusted completion is enabled after publication.
v2 · Activity 3 of 4 · updateasync · session-ownership · stale-writes · 28 min Requires Roblox Studio
UpdateAsync transforms the current value atomically. Returning nil cancels that update. Its callback may be called again and cannot yield, so it must not contain waits, remote calls or an external reward side effect.
An ownership token identifies the session permitted to write. A lease expires, so every save must check both token and expiry. A server that lost ownership must stop state-changing play and saving rather than keep overwriting.
Create OwnedUpdate.apply(current,sessionId,now,newCompleted). Return nil for absent/invalid version, wrong owner, or expired lease. Otherwise copy the new completed sequence into a new record, retaining owner/expiry. Test stale owners and expiry boundaries.
Interface: Complete the documented Studio hierarchy and self-check the behavior outside the browser.
| Input | Expected |
|---|
if record.owner ~= sessionId then return nil end
if record.expiresAt <= now then return nil endMatching an old token is insufficient when its lease has already expired. Both conditions protect this update decision.
New syntax: updateasync, session-ownership, stale-writes
Your explanation is a self-check. Exact wording is not automatically graded.
Self-checked Studio exercise. A saved checklist records your own review; no uploaded place file or screenshot is executed here.
ServerScriptService/OwnedUpdate (ModuleScript) ServerScriptService/TestOwnership (Script, RunContext=Server)
Main guided reference implementation; use the hierarchy’s stated Script or ModuleScript type.
local OwnedUpdate = {}
function OwnedUpdate.apply(current, sessionId, now, newCompleted)
if type(current) ~= "table" or current.version ~= 1 then return nil end
if current.owner ~= sessionId or type(current.expiresAt) ~= "number" or current.expiresAt <= now then return nil end
return { version = 1, owner = current.owner, expiresAt = current.expiresAt, completed = table.clone(newCompleted) }
end
return OwnedUpdateControlled stale/expired/current session cases without live datastore writes.
local Update = require(script.Parent.OwnedUpdate)
local old = { version = 1, owner = "session-a", expiresAt = 100, completed = {"lamp"} }
assert(Update.apply(old, "session-b", 50, {"gate"}) == nil)
assert(Update.apply(old, "session-a", 100, {"gate"}) == nil)
local nextRecord = Update.apply(old, "session-a", 50, {"lamp","gate"})
assert(nextRecord and #nextRecord.completed == 2 and #old.completed == 1)
print("Ownership decision checks passed")Shows the nonyielding trusted transform call. Store access, lease acquisition and retries remain external reviewed responsibilities.
-- Integration sketch for a separate reviewed test environment, not a complete save system.
local function updateOwnedRecord(store, key, sessionId, now, snapshot, OwnedUpdate)
return pcall(function()
return store:UpdateAsync(key, function(current)
return OwnedUpdate.apply(current, sessionId, now, snapshot)
end)
end)
end
return updateOwnedRecordReturning nil cancels a write; do not interpret a successful pcall alone as a confirmed updated record.
Session identity needs a unique server-generated token; Studio JobId may be empty, so a real design must account for that explicitly.
This is a bounded learning lab. It has not been executed in an approved Roblox Studio environment by this website.
A checked checklist records your own review, not automated project competence or a community verification.
UpdateAsync transforms the current value atomically. Returning nil cancels that update. Its callback may be called again and cannot yield, so it must not contain waits, remote calls or an external reward side effect.
An ownership token identifies the session permitted to write. A lease expires, so every save must check both token and expiry. A server that lost ownership must stop state-changing play and saving rather than keep overwriting.
This module tests one ownership decision with controlled records. It is not a datastore framework. Acquisition, renewal, ordered retries, release, shutdown, migration and crash recovery require an extensively tested reviewed design. The official reference also warns against using its sample unchanged.
Replace this code with the starter? Download your draft to keep a copy.
Edit and run these files in Roblox Studio. This browser has no Roblox services, physics, or replication.
Your output will appear here.
Sign in with RoCreators to save private progress across devices. Community verification is separate.