Handling a cross-server market using DataStores

Hello Developers!

I have a really interesting problem I’ve encountered and I don’t know any options on how to handle this problem. My problem is that when adding a market listing to the datastore I will have to request the current listings then add a new listing to the table but my issue with this method is that if someone else is creating a listing near or exactly at the same time that one listing will be saved before the other resulting in the other listing just being lost.

My only solution that I have thought of will be to save every players listing to their own datastore key but if another player requests to see all the current market listings, to my knowledge you cannot request each key that is in a datastore.

What are your thoughts and solutions to this?


For anyone who is having the same issue here is some information I can provide after everyone’s opinions I’ve learnt that:

  • Using MessagingService may not be a good solution due to it failing frequently.
  • UpdateAsync() automatically handles requests one by one but if under stress can still fail.
  • Certain datastore functions cache.
  • Using OrderedDataStores can be a possible solution but requires communication between two datastores.

Overall using UpdateAsync() will work.

2 Likes

An idea i have is a method of storing the data based on an ordered key. For example , if im the first person to create the list you save to datastore with the key “1” and the value as my list and containing my user details. If a second person creates it , it saves it with the key “2” and the value as their list , and it goes in such an order. You could save the latest key to another datastore which determines the length of the main datastore . And your game can periodically get the length of the datastore do a numeric loop from 1 to the length and get the data and display it for all players.

Something like :

local Length = lengthData:GetAsync("Length")
for i = 1 , Length do
 local s , data = pcall(function()
   return Main:GetAsync(i)
 end
 if s and data then 
--display for all players 
 end
end

EDIT : This is just a pseudo code and method , you would have to add safety measures to prevent datastore errors and try adding your own logic.

Thanks for providing a possible solution but my issue with this method is that I will have to request the datastore a lot of times to receive all the data which will result in a lot of requests dropping. This is the same issue I provided in my possible solution.

Maybe using MessagingService and a queue will work?

How often are you gonna update the list?

MessagingService could work i guess , but if you have like a shutdown or something all the data will be gone.

Well depends on the player count, I’ll be requesting and setting data every time a player wants to list a item on the market.

As you can see here it has a 6 second cooldown for each key , so it won’t be a big issue if you add some safety checks.

Well too my understanding of your method you are saying to save each market listing as it’s own key in numerical order in the datastore. If there is 100 Item listings and a player would like to request to see the catalog of the market that means it would take upwards of 600 seconds to load the catalog.

Or are you saying this market data is updated every 600 seconds a player just requests the current data?

How would it take 600 seconds? Are you going to frequently update the list like every second?

You could get the length and loop through the datastore like every 30 or 60 seconds and maybe even cache the data , that would be fine imo.

Sorry let me explain what I’m actually doing more in depth.
Within my game there is limited items and a player has the option to sell it on this cross-server market where other players can go to the market and purchase the item off them (All handled within a UI). I’m 99% sure that there will be 1000+ items listed at one certain time and if we do the math here it’s going to take a long time to update that frequently.

Oh i totally interpreted it in a different way , so once a player decides to sell a limited does it exist there forever until someone buys?

I could add a timeout but for now lets say it’s infinite.

MessagingService would be appropriate here , but the only concern I have is incase of a shutdown when all players gets kicked all the servers get reset and data would be gone too , you could use datastore but it would show the problems you mentioned , have you tried the idea of an external database?

GlobalDataStore | Roblox Creator Documentation lets you update a key based on the current value, so there’s no data loss possible.

Personally I was thinking of using MessagingService and a queue for listing items but I feel like it will be very unreliable as I’ve heard it fails a lot. As for external datastores I’d rather not have to resort to that as I know more about Roblox’s datastores and plus that it costs money.

Either way data is still over-writable if two or more players request to list an item on the market near or at the exact same time.

No, the function you pass to UpdateAsync would be called atomically.

If two players called it at the same time, Roblox would order them and only execute one at a time.

Edit: from that page

In cases where another game server updated the key in the short timespan between retrieving the key’s current value and setting the key’s value, UpdateAsync() will call the function again to ensure that no data is overwritten. The function will be called as many times as needed until the data is saved.

Yes but updateasync() only works on pre-existing data not adding data?

you can just setasync when someone adds a new entry though

I figured you were saving all items in one big array under the same key—otherwise how would you be able to get a list of all items?

Just realized that. I’ll try it out, thanks!

1 Like