That could solve the issue of over writing , but he told that the datastore would be requested multiple times extensively by the players , so it could cause the datastore to drop few of the requests.
UpdateAsync is good for this if you set up your DataStore table in a queue-like manner and use barebones identifiers to track listing data. That meaning, divorce as much as you can from the data and only save what could affect a purchase. Assign IDs to items, modifiable data (e.g. selling cost) and seller information (e.g. UserId) at the bare minimum.
Regarding the queue system, UpdateAsync is careful to respect other DataStore write requests so what you can do is directly mutate the table and add your listing in with each call. There’s probably the issue of caching but you can hard refresh the cash since UpdateAsync is a callback that’ll return with the saved data after calling it.
Current methods of making a cross-server market are pretty scuffed and tedious so in my honest opinion I’d wait for DataStore v1.1 and/or ephemeral DataStores. Ephemeral DataStores are like DataStores but they’re designed for mass reading and writing without permanency and one of the listed use cases is a global marketplace. Sounds perfect for your game.
Understandably though some features can’t wait that long, there’s no telling when we’ll get to see ephemeral DataStores roll around.
I’d suppose OrderedDataStores also work if you can keep track of that. You can use something similar to the DataStore2 method where your value is the listing’s ID and a key in a DataStore corresponds with the ID of that listing.
Is something as simple of this work?
MarketDatastore:UpdateAsync("Listings", function(Listings)
Listings[Player.UserId] = {
["Price"] = Price,
["ItemID"] = ItemID,
["Earnings"] = math.floor(((Price * 90) / 100) + 0.5),
["Claimed"] = {false, nil}
}
return Listings
end)
There’s a limit of 60 + (number of players * 10) read requests per minute, per server. That seems high enough for a store page to me
If the player is only allowed one listing and you don’t mind that the previous listing will be overwritten by a new one if the player can list something else then yes that’s sufficient enough. I would try to minimise the amount of text you use as much as possible just in case you overstep the 4MB value limit unless you can also split off into other key/value pairs.
I also added this little tidbit at the bottom:
Player requests listing → Save listing ID in OrderedDataStore → Save listing data in a key in a regular DataStore
Would require 2n requests to fetch listing information though and with current limits that’s kind of… yikes. Ephemeral DataStore definitely would resolve this though.
Oh yeah my bad , I forgot about that.
I thought OrderedDataStores didn’t store tables.
Would something like this work instead then?
MarketDatastore:UpdateAsync("Listings", function(Listings)
local Listing = {
["UserId"] = Player.UserId,
["ItemId"] = ItemID,
["Price"] = Price,
["Earnings"] = math.floor(((Price * 90) / 100) + 0.5),
["Claimed"] = {false, nil}
}
table.insert(Listings, Listing)
return Listings
end)
They don’t. The point is that you would use two DataStores for every listing; the OrderedDataStore would be responsible for assigning an ID to the listing and the regular DataStore would be responsible for assigning information to that ID. It’s just an idea that I’m thinking out loud but I’m not particularly sure about the practicality of that or how manageable it is.
Practically I think its a lot for just for a simple market system, storing data within two different types of datastore to work together but you think using updateasync() will work out like shown above? Like @nicemike40 stated Roblox automatically handles the requests one at a time so no data loss happens.
Understandable. Dual DataStores is a battle-tested method so I thought it might have some applicability to your use case but even that got confusing for me to conceptualise in my head. Feel free to forget about it, lol. It’s probably not helpful and will exhaust requests fast.
It’s still possible to lose data if you use UpdateAsync without caution. The benefit is that it will respect requests (it’s not atomic, it’s conditional) so if there’s a confliction with the write attempt by UpdateAsync it will retry in order to make sure what it wants to write gets through, so the important part when using it is that you want to build onto existing data rather than hard overwrite it. Both samples you gave will work appropriately.
The only thing I’m somewhat weary about is the 4MB limit and number of requests you need to perform.
My vote is for this method. It’s easy to reason about and you don’t need anything much fancier.
That should work just fine , just make sure to have the 6 second cooldown before each write request.
I just tested updateasync() under heavy load with sending a lot of requests and it handled it fine and managed to add the listings without any being loss as shown here:
The game isn’t released yet so I will have time to improve upon this method.
Correct. In this case, when I say data loss I’m referring to your code not respecting existing data and overwriting anything that may previously have been saved. This is different from the data loss usually observed with SetAsync which occurs as a result of race conditions from multiple servers attempting to read and write data (developers do tend to forget that GetAsync caches for 4 seconds).
Thanks everyone for providing their opinions and solutions but unfortunately I cannot mark everyone as the solution.
Sorry for reviving this post but would using messaging service to check data between two different servers to see if they are the same a good sanity check as extra security?
In my honest opinion, no, since Roblox doesn’t quite support a dedicated server which would be your single point of truth. It’d be difficult to determine which server has the most up-to-date information and which one you should rely on as the updated source.
It’d be a different story if you were only performing an integrity check to refresh the current server’s cache if the data doesn’t match up but consider how that may bloat your budget consumption per minute if a real time market demands rapid, constant changes.
Couldn’t you use versioning? I don’t think you need a dedicated server to do that.
DataStore:UpdateAsync("Listings", function(Listings)
if oldVersion ~= player.Version.Value then return end
player.Version.Value += 1
local Listing = {
["Version"] = player.Version.Value
}
table.insert(Listings, Listing)
return Listings
end)