@@ -114,14 +114,30 @@ export async function composeRebuild(serviceNames, forceBuild = false) {
114114 await execFile ( 'docker' , args , { cwd : APPS_ROOT } ) ;
115115}
116116
117+ async function freePortsFromCompose ( appName ) {
118+ const relPath = await findComposePath ( appName ) ;
119+ try {
120+ const content = await readFile ( join ( APPS_ROOT , relPath ) , 'utf8' ) ;
121+ const ports = [ ...content . matchAll ( / 1 2 7 \. 0 \. 0 \. 1 : ( \d + ) : / g) ] . map ( ( m ) => m [ 1 ] ) ;
122+ for ( const port of ports ) {
123+ const { stdout } = await execFile ( 'docker' , [ 'ps' , '-a' , '-q' , '--filter' , `publish=${ port } ` ] , { } ) . catch ( ( ) => ( { stdout : '' } ) ) ;
124+ const ids = stdout . trim ( ) . split ( '\n' ) . filter ( Boolean ) ;
125+ await Promise . all ( ids . map ( ( id ) => execFile ( 'docker' , [ 'rm' , '-f' , id ] ) . catch ( ( ) => { } ) ) ) ;
126+ }
127+ } catch { /* ignore */ }
128+ }
129+
117130export async function composeFullRestart ( appName ) {
118131 const allServices = await getAllServiceNames ( appName ) ;
119132 console . log ( `[full-restart] ${ appName } : services = [${ allServices . join ( ', ' ) } ]` ) ;
120133
121- // Suppression de tous les containers
134+ // Suppression de tous les containers de l'app
122135 await execFile ( 'docker' , [ 'compose' , '-f' , MAIN_COMPOSE , 'rm' , '-sf' , ...allServices ] , { cwd : APPS_ROOT } ) . catch ( ( ) => { } ) ;
123136 await Promise . all ( allServices . map ( ( n ) => execFile ( 'docker' , [ 'rm' , '-f' , n ] ) . catch ( ( ) => { } ) ) ) ;
124137
138+ // Libération forcée des ports utilisés par l'app (au cas où un container orphelin les tient)
139+ await freePortsFromCompose ( appName ) ;
140+
125141 // Suppression puis recréation d'un réseau dédié propre
126142 const networkName = `${ appName } -net` ;
127143 await execFile ( 'docker' , [ 'network' , 'rm' , networkName ] , { } ) . catch ( ( ) => { } ) ;
0 commit comments