Resume Sessions After a Restart
Survive socket drops, fresh Lavalink sessions, and full process restarts with the right layer.
"Resuming" is really three different failure modes, each handled at a different layer. They are not alternatives — you generally enable the first two together and reach for the third when the process itself dies.
| What broke | Process alive? | Lavalink keeps the session? | Handled by |
|---|---|---|---|
| Socket blip | Yes | Yes | resumable (Lavalink resume) |
| Fresh session (Lavalink restarted / window expired) | Yes | No | byLibrary (library replay) |
| Process restart | No | — | Rebuild from storage |
Layer 1: Lavalink resume (resumable)
resumable configures the node's Lavalink session to stay alive for timeout seconds if the socket drops. Reconnect within that window and Lavalink hands the same session back — the ready event arrives with resumed: true and the audio never stopped.
const = ({
,
: [{ : 'localhost', : 2333, : 'youshallnotpass' }],
: {
: {
: true,
: 60,
},
},
});This only covers a transient socket drop while your process stays up. If Lavalink itself restarts, or the reconnect misses the window, the session is gone and the next layer takes over.
Layer 2: Library replay (byLibrary)
When the node reconnects on a fresh session (resumed: false) and Hoshimi still holds players in memory, byLibrary replays that state onto the node — reconnecting each player, destroying the empty ones, resending the voice state, syncing the queue and replaying the current track.
const = ({
,
: [{ : 'localhost', : 2333, : 'youshallnotpass' }],
: {
: {
: true, // Layer 1 first...
: true, // ...and this is the fallback when the session is fresh.
async (, ) {
// Your own reconnect logic, then hand off to the built-in one.
await (, );
},
},
},
});byLibrary needs the players in memory
byLibrary replays what the running process still holds. It fires only on a fresh session
(!resumed) and only when there are players to replay — so it complements resumable, it does not
replace it. If the whole process restarted, manager.players is empty and there is nothing to replay;
that is Layer 3.
resumeFn runs only while byLibrary is enabled, and defaults to resumeByLibrary when omitted — so leaving it out keeps the built-in behavior.
Layer 3: Rebuild from storage
If the process restarts, the in-memory queue is gone, so neither layer above has anything to resume. Point a queue storage adapter at a durable backend, and after you recreate the player, repopulate its queue from what was persisted.
// Repopulate the in-memory queue from whatever the storage adapter persisted.
await ...({ : true });syncCurrent: true also restores queue.current; see Restore the current track and position to resume playback from where it left off.