Don't make your game state so complex that sending it takes so long that the normal update stream is no longer valid. If your network layer can deal with lag of up to 3s, for instance, you need to be able to send the necessary state in under 3s.
There's no specific architecture to this. Since sending the initial state is almost identical to just sending an update for every object in the client's area of interest (plus a relatively minor set of additional data), and since you're already hopefully working hard to handle the case where you must update every object in the client's area of interest, there's not much more to do.
The only really big architecture thing to consider is that area of interest bit. Don't try to literally send the whole game state. The client doesn't need information about far-away objects, nor does it need to know the value of every single property of nearby objects; it just needs the data to do reasonable prediction and simulation to make gameplay smooth. This has nothing to do with desync directly; this is just good network programming for games.
To handle area of interest properly, you need a NewObject message type (or set of messages) that you have to be prepared to send to the client as the player moves or objects around the player move. Joining a game just means sending a bunch of those for all objects near the area the player is entering the game (same as when a player teleports or respawns, really), and then a few messages about some other global state (team scores, player inventory, which skins/models/names the other players are using, etc.) but nothing that should take an exorbitant amount of time to send.
You can try to multiplex update and setup messages. Don't actually make the player "in the game" until it has all the necessary data. That way you can intermix update messages with "team score" messages if there is a problem with bandwidth or dropped packets, but again, this should not be necessary. Implementing message priorities help with them; keep the initial setup messages at very low priority so that they can't use up all the bandwidth if update messages are being generated. Once the client has enough initial state to play, the player's avatar can be spawned in-game on the server and he can start playing.
One case where this technique is handy is in low-importance but large-size data, like a team's custom logo or a player's custom skin. You don't need this data to play. You can stream it after the player actually joins. If priorities and bandwidth limits means it takes 5s for that purely-visual data to come across, no problem. The game plays just fine without it.
If you're having trouble getting game state across, you're either just sending too much irrelevant data or there's a serious connection problem and reconnecting should just fail; no reason to join a game that'll just desync again shortly because the connection is bad. If the client can't even reconnect and join properly without problem, it should stop trying to reconnect to help try to reduce server load in the event that the problem is an overloaded server.