@@ -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