Updating Server Without Shutting It Down

So I’ve been looking at Merely’s soft shutdown open-source code (Soft Shutdown Script) which allows you to teleport all players in the game to a new server when an update is published and then teleport back after a certain amount of time which should be enough time for the servers to auto-shutdown. This of course is to make sure you don’t lose players.

However, how would you achieve this without shutting down the server at all? Perhaps you’re saving objects in there and you would like to keep them there when you update your game, while the server still being updated to the latest version. Is there any way to do this?

I’ve tried using TeleportData to pass data between the server teleportations, but I couldn’t get it to work.

4 Likes

Reserving shut down servers, is the way to do it.

1 Like

Could you please elaborate on this?

1 Like

Not the best on this but i got a basic idea on it, Using teleport service u could reserver a server and when ur shutting down teleport them to the reserverd server. If u want them back u could teleport them back into a new server.

1 Like

That’s not what I wish to know how to do. As I said, I want to update a server without shutting it down, I’ve already figured out that part based on the code of Merely’s soft shutdown.

1 Like

Okay, u could perhaps update all the items? that might work…

1 Like

I don’t think this is possible, in order to apply changes to a place, the server needs to shutdown.

1 Like

This would require all your game code, assets, UI, etc to be in one central location, clean the server files on launch, then copy the new code into the game for use.
The initialiser would then grab the updated code via Insert service.

You would also need some sort of listener to check the version of your game servers, or to just listen for something (like Amazon SQS) to run the initialiser.

I’ve been meaning to work on this sort of system myself, but haven’t got around to it yet.

You could use an initialiser like this.

But you need to set up so your code defensively to check if an identical asset exists, or create extensive cleaner scripts on both the Client and Server to prepare for the initialization.

I’m actually creating something like this for a future project. I’ll try my best to explain clearly how it works, though be aware that this is quite complex:

  1. Create all your scripting in modules, using a single Script and a single LocalScript to load and initialise all the modules which then do all the actual functionality.
  2. Create your entire map. If you use Terrain then this may be more complex, but without Terrain It’s straightforward.
  3. Store all of the modules, any GUI, any tools, and the map in a Model, organised into Folders of what goes in what service, along with an IntValue to hold the version number. Set the value to 1, and increment this each time you make a change that you want to cause a refresh. Publish the Model to Roblox and set it private.
  4. Clear these things out from the game, so all you’re left with is the Script and the LocalScript that are meant to set up the modules.
  5. The server Script also needs some extra functionality - it needs to pull the model we’ve created using the InsertService:LoadAsset method. It will need to do this once when the server first initialises to load everything in. This script will parent everything to where it needs to be, and initialise the server modules.
  6. You also need to now load this same Model every 5-10 minutes or whatever interval you like, using the methods InsertService:GetLatestAssetVersionAsync and InsertService:LoadAssetVersion. Check the IntValue version number against what you loaded when the server started - if the model now has a larger number, you need to refresh. If not, just discard of this and pull it again in 10 mins or so.

When version is different and you need to refresh:

  1. Your server script will need to do a number of actions to properly reinitialise as if it was never set up.
    (1) Teleport players away OR destroy their characters, prevent respawn, and give them a temporary UI - probably use a RemoteEvent:FireAllClients.
    (2) Clear Workspace, ReplicatedStorage, StarterPack, etc. Clear absolutely everything other than the Script and LocalScript we started with.
    (3) Parent all of the stuff from the new model version.
    (4) Re initialise all of the modules by requireing the new ones and then calling any initialisation functions.
    (5) If you kept the players in, RemoteEvent again to say it’s safe to reinitialise so the LocalScript knows it can now reinitialise all the client modules and display the new UI and hide any temporary UI you had.
  2. Once complete, you can then repeat the loop from step 6 to check for any future version changes.

Now that’s a lot. It’s hard to explain in text, but hopefully you understand the gist of it. Essentially:

  • Use a model published to Roblox to hold everything.
  • Use InsertService methods to load it and to get the latest version every so often.
  • If a new version is found, refresh the game automatically in your Script.
  • Up to you whether to keep players or teleport them to a temporary place.

You could extend this further using MessagingService to let other servers know a new version is available so they can skip their current 10 minute wait and just refresh it instantly. There’s a lot you can mess about with.

4 Likes

As for terrain loading, you could probably use something like this if necessary.

2 Likes

That sounds really nice, but I’d rather store the current server’s version in the script instead of an Int Value. I’ll try all of that and see how it works, thanks for the amazing response!

1 Like

The reason not to have it in a script is to prevent needing to require a module each time and/or run a script somewhere just to get the version number and find out it’s the same version as what you already have.

You need a quick way to check the version that does not end up running the same code in parallel by accident.

Therefore if I were to do it in a script I’d have a module that literally does nothing other than hold a version number, in which case I might as well just have an IntValue instead to save a require() line.