To start yes I know there are better systems than this like profile service and so on… but I’m doing this to help me understand better data stores and OOP,
So I’d like some tips on how I could improve this make it more efficient, safer.
Any tips are appreciated, thank you!
function module.new(Name: string, V: number, Scope: string)
local self = setmetatable(module, {})
self.Data_Store = _DS:GetDataStore(string.format(Name.."_%s", tostring(V)), Scope)
return self
end
function module:Get(Key: string)
local success, result = pcall(function()
return self.Data_Store:GetAsync(Key)
end)
if success and result then
return result
else
return nil
end
end
function module:Set(Key: string, Data: any)
local success, err = pcall(function()
self.Data_Store:SetAsync(Key, Data)
end)
if not success then
return nil
end
end
function module:Update(Key: string, Data: any)
local success, result = pcall(function()
self.Data_Store:UpdateAsync(Key, function()
return Data
end)
end)
if not success then
return nil
end
end
function module:Reset(Key: string)
local success, err = pcall(function()
self.Data_Store:RemoveAsync(Key)
end)
if not success then
return nil
end
end
You could add some type of retry system so if the datastore operation fails due to specific network issues, you could retry the request a certain amount of times before giving up.
Also, if I were to use this module and called Get and saw it returned nil, there’d be no way for me to know whether it returned nil because nothing is set at that key or because the request failed. So maybe add a way to differentiate between those two outcomes.
A retry system? You can start with something pretty basic like the following
local NumAttempts = 0
local MaxAttempts = 3
while NumAttempts < MaxAttemtps do
NumAttempts += 1
-- Make data store calls here and do logic based on any errors that happen
-- If it's successful, you can just break out of the loop
end
You can make some higher level function that takes the contains all the logic for retries and takes what you’re supposed to do as an argument. For example
RunRetriableRequest(function()
self._Data_Store:GetAsync(Key)
end
Obviously do whatever works within your setup, but I’d suggest starting simple at first with a basic while loop. From there you can even look into exponential backoff or similar algorithms if you want something more complex.
As for determining when you should retry and when you shouldn’t, I’d recommend looking at the possible errors that can get returned from data store calls and try and differentiate which errors are user errors and which are external uncontrollable errors.
If you look at all the 1XX errors, those are user errors so there’s no point in retrying since if it failed the first time, it’s going to fail every time. However, some of the 4XX and 5XX errors are somewhat uncontrollable so it might be worth retrying the request if you encounter them. You sort of need to make a judgement call on what you deem a user error vs external error.
Also, if with retrying you should be aware of any throttling issues that can occur and try to implement it in a way that avoids that.
Looks great, I even learned something new. Always been going with SetAsync() after looking up UpdateAsync() … This allows for atomic updates and ensures the new value is derived safely, especially in cases where multiple updates might occur simultaneously. I think I’ll add this to my global update. That could happen with that.