Skip to content

Commit b9e7002

Browse files
committed
feat(volume-backups): implement volume backup locking mechanism
- Added a locking mechanism to prevent concurrent volume backups, ensuring data integrity during backup operations. - Introduced a `lockWrapper` function that manages the locking process using either `flock` or directory-based locking. - Updated the `backupVolume` function to utilize the locking mechanism for both application and compose service types, enhancing the reliability of backup processes.
1 parent bc39add commit b9e7002

File tree

1 file changed

+47
-5
lines changed
  • packages/server/src/utils/volume-backups

1 file changed

+47
-5
lines changed

packages/server/src/utils/volume-backups/backup.ts

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export const backupVolume = async (
1010
const { serviceType, volumeName, turnOff, prefix } = volumeBackup;
1111
const serverId =
1212
volumeBackup.application?.serverId || volumeBackup.compose?.serverId;
13-
const { VOLUME_BACKUPS_PATH } = paths(!!serverId);
13+
const { VOLUME_BACKUPS_PATH, VOLUME_BACKUP_LOCK_PATH } = paths(!!serverId);
1414
const destination = volumeBackup.destination;
1515
const backupFileName = `${volumeName}-${new Date().toISOString()}.tar`;
1616
const bucketDestination = `${normalizeS3Path(prefix)}${backupFileName}`;
@@ -45,16 +45,56 @@ export const backupVolume = async (
4545
return baseCommand;
4646
}
4747

48+
const serviceLockId =
49+
serviceType === "application"
50+
? volumeBackup.application?.appName
51+
: `${volumeBackup.compose?.appName}_${volumeBackup.serviceName}`;
52+
53+
const lockPath = `${VOLUME_BACKUP_LOCK_PATH}-${serviceLockId}`;
54+
55+
const lockWrapper = (body: string) => `
56+
set -e
57+
58+
LOCK_PATH="${lockPath}"
59+
60+
echo "Waiting for volume backup lock: $LOCK_PATH"
61+
62+
if command -v flock >/dev/null 2>&1; then
63+
exec 9>"$LOCK_PATH"
64+
flock 9
65+
else
66+
LOCK_DIR="$LOCK_PATH.dir"
67+
while ! mkdir "$LOCK_DIR" 2>/dev/null; do
68+
echo "Waiting for volume backup lock: $LOCK_PATH"
69+
sleep 5
70+
done
71+
trap 'rm -rf "$LOCK_DIR"' EXIT
72+
fi
73+
74+
echo "Volume backup lock acquired"
75+
76+
${body}
77+
78+
echo "Volume backup lock released"
79+
`;
80+
81+
console.log(
82+
lockWrapper(`
83+
echo "Volume backup lock acquired"
84+
echo "Volume backup lock released"
85+
`),
86+
);
87+
4888
if (serviceType === "application") {
49-
return `
89+
return lockWrapper(`
5090
echo "Stopping application to 0 replicas"
5191
ACTUAL_REPLICAS=$(docker service inspect ${volumeBackup.application?.appName} --format "{{.Spec.Mode.Replicated.Replicas}}")
5292
echo "Actual replicas: $ACTUAL_REPLICAS"
5393
docker service update --replicas=0 ${volumeBackup.application?.appName}
5494
${baseCommand}
5595
echo "Starting application to $ACTUAL_REPLICAS replicas"
5696
docker service update --replicas=$ACTUAL_REPLICAS --with-registry-auth ${volumeBackup.application?.appName}
57-
`;
97+
`);
5898
}
5999
if (serviceType === "compose") {
60100
const compose = await findComposeById(
@@ -70,6 +110,7 @@ export const backupVolume = async (
70110
ACTUAL_REPLICAS=$(docker service inspect ${compose.appName}_${volumeBackup.serviceName} --format "{{.Spec.Mode.Replicated.Replicas}}")
71111
echo "Actual replicas: $ACTUAL_REPLICAS"
72112
docker service update --replicas=0 ${compose.appName}_${volumeBackup.serviceName}`;
113+
73114
startCommand = `
74115
echo "Starting compose to $ACTUAL_REPLICAS replicas"
75116
docker service update --replicas=$ACTUAL_REPLICAS --with-registry-auth ${compose.appName}_${volumeBackup.serviceName}`;
@@ -78,16 +119,17 @@ export const backupVolume = async (
78119
echo "Stopping compose container"
79120
ID=$(docker ps -q --filter "label=com.docker.compose.project=${compose.appName}" --filter "label=com.docker.compose.service=${volumeBackup.serviceName}")
80121
docker stop $ID`;
122+
81123
startCommand = `
82124
echo "Starting compose container"
83125
docker start $ID
84126
echo "Compose container started"
85127
`;
86128
}
87-
return `
129+
return lockWrapper(`
88130
${stopCommand}
89131
${baseCommand}
90132
${startCommand}
91-
`;
133+
`);
92134
}
93135
};

0 commit comments

Comments
 (0)