How to properly save data with dev products and when

Hi.

I’m wondering how would I properly make sure that data isn’t lost when someone buys something and server crashes and when should I save data.

I cannot save data for each purchase because of the 6 second cooldown when writing to the same key.

I do have auto saves but what to do if server crashes before data is saved?

I know there’s PurchaseGranted which, after called, confirms that purchase was successful (and if not called, Roblox refunds Robux in 72h afaik). What do most developers do?

Thank you!

You can save data whenever:

  • The player leaves the game.
  • If you’re going to use Autosave, make the interval at least 60.
  • Before the client closes the application or whenever it crashes, essentially DataModel:BindToClose() Here

When using Bind to close, please be reminded that:

Saving when leaving could cause data loses if not written correctly, or it might not have enough time to save the data.

Saving on game shutdown isn’t good either, this could error while trying to save everyone’s datas at the same time, there could be some more reasons why it won’t save with this option.

Saving every 60 seconds is the best option.
I might be wrong, but that’s how I think it.

Edit: another way of saving is between important checkpoints, or something like that. So like if someone in your game passed a story or something, have it save right after. Make sure it doesn’t cause server-lag and don’t save too many times because it can put your async on cooldown

I tried using BindToClose and crashed the server but my data didn’t save.

BindToClose saves only when game shutdown, if I’m not mistaken. If you crash the client, I don’t think it works.

Besides, if it does, you probably used it incorrectly, or, it’s just that problem - didn’t have enough time to save data.

Yeah… To be more specific, I’m testing it with ProfileService and then release the profile when BindToClose runs but it didn’t save data when the server crashed.

So, that’s my main concern regarding dev products in case if the server crashes.

Then I think saving after every dev product purchase could work, but would stress server a lot - not really recommended… might queue saving if you do that.

Is there any reasons servers would crash? Your game can crash your client or what? Or you just want to shutdown servers?
Like I said, try saving every 60 seconds and it should be fine, you can make an extra button that lets you save your data every 240 seconds, and when server shutdowns, use BindToClose and make a message that says “save your data, server is shutting down”, allow players to save their datas (and maybe make the buttons enabled for everyone, just in case). This should be the best way around it.

I don’t really think that servers will crash on their own (I’m currently just testing by running while true do end) unless there’s maintenance or something like that…

That’s why I’m looking for a way that would properly use PurchaseGranted (so when a player buys an item, they would get that item, but PurchaseGranted would be returned once their data is saved (with an auto save) but I can’t really confirm that without running some “repeat until” loop which would check if data was auto saved and that’s unreliable.

You don’t need to use loops to verify if data saved. You can simply use a pcall and if it returns true, it means the data saved.

Yes, you can save after every purchase (make sure to save after the purchase is confirmed!).
And yes, servers shouldn’t crash on their own too.

The reason why I tested it with a loop (there’s a os.time() value in data which changes each time data is saved) is because I’m waiting for an auto save (not the same script as the one with the dev product).

I don’t really want to save data for each purchase in case if they kept buying items faster than the 6 second cooldown.

You can make an extra check, have a cooldown on server side for each player in a table, compare with current time and if it’s bigger than 30 seconds, save it.

local Cooldowns = {};
MarketplaceFunction = function()
--//
if not Cooldowns[Player.UserId] then
Cooldowns[Player.UserId] = 0
end;

if PurchaseVerified then
if tick()-Cooldowns[Player.UserId] > 30 then
--// save
Cooldowns[Player.UserId] = tick(); -- reset cooldown
end;
end;
end;

Something like that should work.
Make sure to remove Player UserId from there when player leaves the game.